Vue 之 More in js

More in js,縱享絲滑開發體驗!javascript

前言

在說 More in js 以前,想必你們對 ReactAll in js 都不陌生,各位看官莫被幹擾,本文與 React 無關。More in js 爲筆者開發過程當中的一些實例嘗試,可能你們都有過相似的開發經歷,但少有人思考這麼作的價值。vue

image.png

SFC 組件結構

講到 Vue 的 SFC 組件結構,你們首先想到的必定是 template script style 三部曲。實際表現形式以下:java

<template>
    ...
</template>

<script> ... </script>

<style> ... </style>
複製代碼

上面的代碼就是 VueSFC 基礎結構了,那這跟咱們的 More in js 又有啥關係呢?react

SFC 常見問題

咱們一般在業務組件開發時,避免不了出現複雜佈局狀況,組件嵌套(一層又一層,層層不同),此時再加上業務邏輯的處理,代碼行數輕輕鬆鬆破 1000+web

那麼在維護或開發此類代碼時,可能就是爲了加一個屬性致使咱們在 templatescript 之間反覆橫跳,開發體驗較差,也帶來了額外的時間成本。(此時某位暴躁老哥已經開始砸鍵盤了!)api

image.png

上圖是筆者開發中的一個畫布組件,其代碼行數不算樣式部分也突破了 2000+,對於正在修改業務邏輯的我忽然須要給視圖組件加個屬性,直接促使腎上腺素飆升!markdown

靈感來源

對於上述問題的解決方案是在業務組件封裝時產生的靈感。app

一般 UI 組件庫的基礎組件並不能知足咱們複雜的業務需求時,會對齊進行二次封裝,那麼對於源組件的 propsevents 咱們也是須要暴露給外界來下降上手成本,只針對該處的場景提供便利性,縱享絲滑體驗。異步

例如:async

<template>
  <Button class="async-button" ref="main" v-bind="mergeProps" :loading="loading" @click.prevent="onClick" > <slot></slot> </Button>
</template>

<script> import { omit, merge } from 'lodash' export default { name: 'AsyncButton', props: { /** * 使用原始 Button 事件 * @default false */ useRaw: { type: Boolean, default: false } }, data() { return { loading: false } }, computed: { mergeProps() { const defaultProps = { type: 'primary' } return omit(merge(defaultProps, this.$attrs), 'loading') } }, methods: { /** * 處理點擊事件。 */ onClick(e) { // useRaw: true 使用原始單擊事件,false 使用異步單擊事件 if (this.useRaw) { this.$emit('click', e) } else { this.loading = true this.$emit('click', () => (this.loading = false), e) } } } } </script>
複製代碼

上面代碼是對 Button 組件作的一層簡單封裝,讓使用者可以在點擊時自動啓動加載狀態,在須要時經過回調函數來關閉加載狀態。

對於源 Button 組件的 props 經過 Vue 提供的 v-bind$attrs 實現屬性穿透,那麼反過來咱們思考下是否能夠把該方式應用到業務組件開發中?

答案是能夠的。

More in js

提出的 More in js 概念就是爲了讓 Vue 開發者可以更好地專一於業務邏輯部分的處理,配合 IDE 的定義跳轉功能,能夠相對的優化上述問題。

<template>
  <SpecialTabs class="data-point-tabs" left-label="上傳文件" right-label="已上傳的文件列表"> <!-- upload start --> <template slot="left"> <SingleUpload ref="singleUpload" v-bind="singleUpload" /> </template> <!-- upload end --> <!-- table start --> <template slot="right"> <!-- table --> <Table class="file-table" v-bind="table" @hook:created="loadTableData" /> <!-- modal start --> <Modal v-bind="modal" v-model="modal.show" transfer> <!-- modal footer --> <template slot="footer"> <Button @click="toggleModal(false)">取消</Button> <Button v-bind="confirmBtn" @click="submitForm">肯定</Button> </template> <!-- edit form --> <EditForm ref="editFormRef" :key="`edit-form_${updateFormFlag}`" :info="table.singleSelected" @on-validated="handleValidated" @on-submitted="handleSubmitted" ></PointForm> </Modal> <!-- modal end --> </template> <!-- table end --> </SpecialTabs>
</template>

<script> import SpecialTabs from '@/components/SpecialTabs' import SingleUpload from '@/components/SingleUpload' import { dataPointColumns } from './entity/data-point' import DeleteMixin from '@/mixins/delete' import EditForm from './components/edit-form.vue' import { showErrorMessage } from '@/util/error' export default { name: 'DataPoint', mixins: [DeleteMixin], components: { SpecialTabs, SingleUpload, EditForm }, data() { return { singleUpload: { autoUpload: true, loading: false, uploadRequest: this.uploadRequest, beforeUpload: this.handleBeforeUpload }, table: { border: true, loading: false, disabledHover: true, columns: dataPointColumns.call(this), data: [], singleSelected: {}, actionOptions: [...] }, modal: { title: '配置表單', maskClosable: false, show: false }, confirmBtn: { type: 'primary', loading: false }, updateFormFlag: 0 } }, computed: { /** * DeleteMixin */ deleteOption() { return { deleteUrl: '/db_table/delete', method: 'delete', loading: true, params: (selection) => ({ table_name: selection[0].table_name }), afterDelete: (flag) => flag && this.loadTableData() } } }, methods: { ... } } </script>
複製代碼

上述代碼是對 More in js 的一次嘗試,組件的屬性對象顯示聲明在 data 中,經過 v-bind 來動態綁定到模板上,可以提高代碼的閱讀性,讓開發者更加專一業務邏輯層,對於視圖層只關注在佈局便可。

image.png

配合 IDE 的定義跳轉功能,可以輕鬆實現對視圖層組件的屬性控制及添加,減小代碼橫跳次數,提高開發效率。

Vue3 更優體驗

Vue2 中因爲 options api 的結構,咱們的組件開發一般在單文件中,不會對內部業務邏輯過於聚合,因此 More in js 方式只會解決單文件內部的代碼橫跳問題。

可是在 Vue3hooks api 中,咱們能夠經過抽離業務邏輯到 @use/xxx 後,讓視圖層與邏輯層的代碼高度聚合,使用 More in js 能夠更好的維護組件狀態,不須要頻繁的切換文件來更新屬性信息。

// dp.vue
<template>
  <SpecialTabs class="data-point-tabs" left-label="上傳文件" right-label="已上傳的文件列表"> <!-- upload start --> <template slot="left"> <SingleUpload ref="singleUploadRef" v-bind="singleUploadAttrs" /> </template> <!-- upload end --> <!-- table start --> <template slot="right"> <!-- table --> <Table class="file-table" v-bind="tableAttrs" @hook:created="loadTableData" /> <!-- modal start --> <Modal v-bind="modal" v-model="modal.show" transfer> <!-- modal footer --> <template slot="footer"> <Button @click="toggleModal(false)">取消</Button> <Button v-bind="confirmBtn" @click="submitForm">肯定</Button> </template> <!-- edit form --> <EditForm ref="editFormRef" :key="`edit-form_${updateFormFlag}`" :info="tableAttrs.singleSelected" @on-validated="handleValidated" @on-submitted="handleSubmitted" ></PointForm> </Modal> <!-- modal end --> </template> <!-- table end --> </SpecialTabs>
</template>

<script setup> ... const { singleUploadAttrs, ... } = useUpload() const { tableAttrs, ... } = useTable() </script>


// @use/upload.js
...

export default function useUpload() {
    const singleUploadAttrs = reactive({
        autoUpload: true,
        loading: false,
        uploadRequest: uploadRequest,
        beforeUpload: handleBeforeUpload
    })
    
    function uploadRequest() {...}
    
    function handleBeforeUpload() {...}
    
    ...
    
    return { singleUploadAttrs, ... }
}


// @use/table.js
...

export default function useTable() {
    const tableAttrs = reactive({
        border: true,
        loading: false,
        disabledHover: true,
        columns: dataPointColumns(),
        data: [],
        singleSelected: {},
        actionsOptions: [...]
    })
    
    function loadTableData() {
        ...
        
        tableAttrs.data = [...]
    }
    
    ...
    
    return { tableAttrs, ... }
}
複製代碼

Volar 體驗提高

隨着 Vue3 的穩定,IDE 方面的插件也有了新的支持,官方維護的 Volar 脫穎而出,這裏只重點說明 Volar 的編輯器拆分功能來讓體驗更加絲滑。

image.png

經過拆分編輯器,配合 More in js 方式,只須要關注左側 hooks 代碼便可讓開發體驗上升一個臺階。

總結

本次靈感主要解決開發時繁瑣的代碼橫跳,從而找出更優的開發體驗,但非最優體驗,因人而異,請各位看官勿噴。有何問題,可評論區留言,謝謝!

相逢便是緣,揮一揮手指,留下一個贊吧!(^▽^)

image.png

相關文章
相關標籤/搜索