【vue系列】優雅地用 vue 生成動態表單(二)

歷史回顧:javascript

需求背景

工做臺模塊,新需求要作請假審批,開需求評審的時候,瞭解到請假有:年假 、病假、調休、事假 、婚嫁、喪假期、產假、陪產假等8種類型。筆者第一個想法就是不想寫多個表單頁面,也不想在一個表單頁面中寫不少的判斷類型邏輯。因而就試探性詢問可否由後端配合作動態表單,畢竟以前作一次。可是後端和產品都一致認爲此次表單的變動不大,不必再開發一個表單的配置系統。不開心吶,需求評審完成以後筆者開始調研實現方案和技術選型。html

尋找技術方案和技術選型

思考着可否由前端全權動態表單操控處理?這樣就能夠減輕後端的開發時長和壓力,固然此次需求就比較重前端了。那就來個動態表單,根據不一樣的請假類型,自動生成表單,雖然在首次開發須要更多的思考和設計,可是後期方便維護啊。筆者也是對需求、對業務、對代碼有要求的人。哼~前端

那麼問題來了,若是採用動態表單的話,小程序並無動態組件能夠方便處理,因而筆者考慮選用小程序內嵌h5的方式,h5採用vue框架。技術方案和技術選型就肯定好了。vue

針對8種請假類型:年假 、病假、調休、事假 、婚嫁、喪假期、產假、陪產假的表單,提煉出須要用到的組件,以及須要生成動態表單的配置表。java

動態組件那些事

這份組件圖,主要給咱們的內部開發人員看,一目瞭然地知道怎麼去作代碼的組織和構建。下面總結了動態表單由哪些組件組成,各個組件之間的關係和依賴,以及組件依賴的三方和框架。算法

總結須要開發的組件有:vue-router

  • 日期選擇器(依賴 mint-ui 的 datetime-picker)
  • 帶上、下午的日期選擇器(vue-halfday-datepicker插件,針對底層使用的 mint-ui 的picker二次封裝的npm)
  • 請假時長計算器( leave-days-calculator插件,依賴開始和結束時間)
  • 結束時間自動計算器(依賴開始和請假時長,下期開發~)
  • 多行輸入框組件
  • 上傳圖片組件(針對內部上傳組件二次封裝)

其中 請假時長計算器 在筆者的造輪子 | 如何開發一個請假時長計算器?這篇文章中查看實現細節和詳情,帶上、下午的日期選擇器 能夠查看筆者vue-halfday-datepicker插件的封裝過程這篇文章。vuex

建立組件的細節請參考【vue系列】優雅地用 vue 生成動態表單(一),這裏就再也不贅述了。npm

動態表單配置表

動態組件開發完成,動態表單的配置表就能出來了。element-ui

// 請假類型的map表,同後端一一對應
export const typeObj = {
    1: '年假',
    2: '病假',
    3: '調休',
    4: '事假',
    5: '婚假',
    6: '喪假',
    7: '產假',
    8: '陪產假',
    9: '補假',
}

/**
 * 全部請假表單的動態配置config
 */
export const setFormConfig = {
    // 年假
    1: [
        {
            "name": "start_time",
            "type": "halfdaydate",
            "title": "開始時間",
            "prompt_msg": "請選擇",
            "val": null,
        }, 
        {
            "name": "end_time",
            "type": "halfdaydate",
            "title": "結束時間",
            "prompt_msg": "請選擇",
            "val": null,
        }, 
        {
            "name": "leave_length",
            "type": "leavelength",
            "title": "請假時長",
            "prompt_msg": "請選擇",
            "val": null,
        }, 
        {
            "name": "notes",
            "type": "multiple",
            "title": "請假事由(必填):",
            "prompt_msg": "請輸入請假事由",
            "val": null,
        }
    ],

    // 病假
    2: [
        {
            "name": "start_time",
            "type": "halfdaydate",
            "title": "開始時間",
            "prompt_msg": "請選擇",
            "val": null,
        }, 
        {
            "name": "end_time",
            "type": "halfdaydate",
            "title": "結束時間",
            "prompt_msg": "請選擇",
            "val": null,
        }, 
        {
            "name": "leave_length",
            "type": "leavelength",
            "title": "請假時長",
            "prompt_msg": "請選擇",
            "val": null,
        }, 
        {
            "name": "notes",
            "type": "multiple",
            "title": "請假事由(必填):",
            "prompt_msg": "請輸入請假事由",
            "val": null,
        }, 
        {
            "name": "imgs",
            "type": "images",
            "title": "上傳圖片:",
            "prompt_msg": "請上傳圖片",
            "val": null,
        }
    ],

    // 調休
    3: [
        {
            "name": "start_time",
            "type": "halfdaydate",
            "title": "開始時間",
            "prompt_msg": "請選擇",
            "val": null,
        }, 
        {
            "name": "end_time",
            "type": "halfdaydate",
            "title": "結束時間",
            "prompt_msg": "請選擇",
            "val": null,
        }, 
        {
            "name": "leave_length",
            "type": "leavelength",
            "title": "請假時長",
            "prompt_msg": "請選擇",
            "val": null,
        }, 
        {
            "name": "overtime_compensation",
            "type": "date",
            "title": "調休替代日期",
            "prompt_msg": "請選擇",
            "val": null,
        }, 
        {
            "name": "notes",
            "type": "multiple",
            "title": "請假事由(必填):",
            "prompt_msg": "請輸入請假事由",
            "val": null,
        }, 
        {
            "name": "imgs",
            "type": "images",
            "title": "上傳圖片:",
            "prompt_msg": "請上傳圖片",
            "val": null,
        }
    ],

    // 事假
    4: [
        {
            "name": "start_time",
            "type": "halfdaydate",
            "title": "開始時間",
            "prompt_msg": "請選擇",
            "val": null,
        }, 
        {
            "name": "end_time",
            "type": "halfdaydate",
            "title": "結束時間",
            "prompt_msg": "請選擇",
            "val": null,
        }, 
        {
            "name": "leave_length",
            "type": "leavelength",
            "title": "請假時長",
            "prompt_msg": "請選擇",
            "val": null,
        }, 
        {
            "name": "notes",
            "type": "multiple",
            "title": "請假事由(必填):",
            "prompt_msg": "請輸入請假事由",
            "val": null,
        }
    ],

    // 婚假
    5: […],
    // 喪假
    6: […]
    // 產假
    7: […],
    // 陪產假
    8: […]
]
複製代碼

動態組件統一管理

動態組件統一導入導出,方便管理,後期增、刪、改這一個文件就夠了。

// 多行文本輸入框組件
export { default as Multiple } from './multiple.vue' 

// 上傳圖片組件
export { default as Images } from './images.vue' 

// 日期選擇器組件(成天)
export { default as Date } from './date_picker.vue' 

// 半天日期選擇器組件(上/下午)
export { default as Halfdaydate } from './halfdaydate_picker/index.vue' 

// 請假時長計算器
export { default as leavelength } from './leaveLength/index.vue'
複製代碼

在動態表單頁面,統一動態引入,經過 component 動態組件的方式渲染,還不瞭解vue動態組件的戳這裏 動態組件 & 異步組件

<template>
    <div class="g-context">
        <section class="form-wrap">
	    // …
            <component 
                v-for="(item, number) in freedomConfig" 
                :key="item.name"
                :is="item.type" 
                :item="item" 
                :preFormData="preFormData"
                :number="number"
                @changeComponent="changeComponentHandle"
            ></component>
        </section>
         // ….
    </div>
</template>

<script>
// …
import * as itemElements from '../../components/itemElement'

export default {
    // …
    props: ['type'], // type 請假類型
    components: itemElements,
}
複製代碼

經過請假類型和動態表單的配置表,結合動態組件,將準確的顯示各個請假類型須要的表單,表單數據彙總和校驗的方式跟【vue系列】優雅地用 vue 生成動態表單(一)幾乎同樣,能夠去這篇查看細節處理。

其中關於 請假時長計算器 的處理,須要根據,開始時間和結束時間動態計算,這裏再具體說說。 動態組件生成的屬性 :preFormData="preFormData」preFormData 是整個表單的數據彙總,透出給各個組件,在 請假時長計算器組件中 watch 該屬性。

watch: {
    preFormData: {
        handler(v, o) {
            this.throttleHandle(() => {
                const { start_time, end_time} = v

                // 公共方法計算出請假時長
                let leaveDays = leaveDaysCalculator(start_time, end_time)
                this.value = leaveDays

                this.$emit('changeComponent', {
                    number: this.number,
                    value: leaveDays
                })
            })
        },
        deep: true,
        immediate: true
    }
},
複製代碼

須要注意下 watch 的用法,這使用了 deep、immediate 屬性,其中 deep: true表明深度監聽,immediate: true 表明該回調將會在偵聽開始以後被當即調用, 還不清楚用法的戳 watch的用法

小結

筆者的處理方法不必定是最優的,或者能夠採用雙向數據綁定的方案。整體上來講,我想作的事情想把如何建立動態表單的思路,以及設計方案表述出來作個記錄,也不知道講清楚了沒有🤦‍♀️。若是你有好思路或者疑惑,歡迎在評論區留言與我討論。業界目前已經有很完善的解決方案,好比阿里的 [Formily](https://formilyjs.org/#/bdCRC5/dzUZU8il),你們能夠自行學習瞭解,看了別人方案,發現本身還有更多須要學習的地方,加油~

相關文章
相關標籤/搜索