Vue2 Element Schema Form 配置式生成表單的實(shí)現(xiàn)
前置知識(shí)點(diǎn)
為了實(shí)現(xiàn)一個(gè)Schema Form
配置式表單的生成,需要了解一部分前置知識(shí)點(diǎn)。
Component
vue
提供了一個(gè)內(nèi)置組件 Component
,用來動(dòng)態(tài)渲染組件,舉個(gè)例子,本篇文章以Element UI
為例,假設(shè)我們?nèi)肿粤?code>Element UI的組件,那么下面一段代碼
<Component is="el-input"></Component>
將被渲染為el-input
組件。
好了,最重要的實(shí)現(xiàn)知識(shí)點(diǎn)已經(jīng)完了,只要了解了這一點(diǎn),我這個(gè)Schema Form
的實(shí)現(xiàn)思路,你就能完全看懂了,就這么簡單。
但是為了我們表單的易用性,我們再了解一點(diǎn)兒其他的。
比如Component
組件并非只能接收一個(gè)字符串,渲染全局組件,同時(shí)可以接收一個(gè)Component
組件,也就是說,當(dāng)我們Element UI
組件沒有全局注冊的時(shí)候,我們可以通過import { ElInput } from 'element'
,傳遞給Component
組件,同樣可以完成渲染一個(gè)el-input
組件的功能。
$attrs
第二個(gè)知識(shí)點(diǎn),vue
的屬性透傳
,假如你有這么一個(gè)疑惑 —— 我對(duì)el-input
進(jìn)行了二次封裝
,那el-input
接收的props
我是否需要在二次封裝的組件
中進(jìn)行props的定義,再逐一傳遞給el-input
才能生效。
如果有這樣的疑惑那么$attrs
可以幫你,對(duì)于二次封裝的組件,通過定義v-bind="$attrs"
,傳遞給父組件的屬性即可透傳給el-input
,于是就有了這么一個(gè)疑問,$attrs
可以綁定給v-bind
,那么一個(gè)普通的對(duì)象可以嗎,答案是可以的。
這是我們 schema form
變得好用的第二個(gè)重要的知識(shí)點(diǎn)。
$listeners
與 $attrs
相同,做事件透傳的,通過v-on
綁定。
以上就是我認(rèn)為,實(shí)現(xiàn)Schema Form
配置式生成表單所需要掌握的全部知識(shí)及擴(kuò)展思考,接下來,我們簡單完成一個(gè)配置式表單.
表單的結(jié)構(gòu)是什么樣的
1、我可能希望對(duì)表單進(jìn)行一部分特殊的處理,所以,包一層div
總是沒錯(cuò)的,當(dāng)然,這是我的習(xí)慣,你們可以自行選擇。
2、既然是表單,那一定被el-form
包裹。
3、為了配置式布局的需要,我希望引入el-row el-col
柵格系統(tǒng)
4、無論如何完善表單,必然不可能滿足所有要求,那最簡單的方式就是拋出slot
5、有些時(shí)候我希望渲染文本呢?有些時(shí)候我希望渲染字段的值而不涉及任何組件呢?
6、最后才是渲染對(duì)應(yīng)的組件
那么,一個(gè)表單的結(jié)構(gòu)化雛形就完成了。
<div class="schema-form"> <el-form> <el-row> <el-col v-for="item in config" :key="item.key"> <el-form-item> <slot v-if="item.component === 'slot'" :name="item.slotName"></slot> <div v-else-if="item.component === 'innerText'"></div> <template v-else> 渲染對(duì)應(yīng)組件,但需要對(duì)某些組件特殊處理 </template> </el-form-item> </el-col> </el-row> </el-form> </div>
從上面的結(jié)構(gòu)中,我們再來思考,我們的配置config
數(shù)組的字段結(jié)構(gòu)應(yīng)該是什么樣的。
配置數(shù)組數(shù)據(jù)結(jié)構(gòu)
1、el-form
可能需要一些字段注入,作為最外層的組件,將傳入schema form
的字段都給它
2、el-form
需要傳入一個(gè)數(shù)據(jù)源,這個(gè)數(shù)據(jù)源可以內(nèi)部定義再傳給外部,也可以傳入一個(gè)對(duì)象,利用對(duì)象的特性做雙向綁定,我選擇了后者
3、el-col
項(xiàng)可能有時(shí)不顯示,所以config
上擴(kuò)展一個(gè)字段hidden
,用于控制該項(xiàng)是否顯示。
4、el-form-item
的屬性透傳
5、innerText
的樣式定義
一些特殊的描述出來了,其余的再贅述,那么,config
的數(shù)據(jù)結(jié)構(gòu)就是這樣
{ key: '', // 當(dāng)前字段的 key 值,同時(shí)會(huì)傳到 el-form-item 的prop,不傳數(shù)據(jù)驗(yàn)證和重置會(huì)失效 label: '', // 當(dāng)前 el-form-item 的label hidden: '', // 當(dāng)前表單項(xiàng)是否展示 labelWidth: '', // el-form-item 的label寬度 component: '', // 支持 slot、innerText、Component,渲染成什么 slotName: '', // compoment 為 slot 時(shí),該值為對(duì)應(yīng)slot的名字供外部使用 innerClass: '', // component 為 innerText 時(shí),給文本的樣式,通常為全局樣式 innerStyle: '', // 同上 innerText: '', // component 為 innerText 時(shí),優(yōu)先顯示的文本,否則會(huì)顯示當(dāng)前的字段值 itemProps: '', // 注入到 el-form-item 的屬性 props: '', // 當(dāng) component 為渲染組件時(shí),注入到渲染組件當(dāng)中的屬性 listeners: '', // 當(dāng) component 為渲染組件時(shí),注入到渲染組件當(dāng)中的事件 }
當(dāng)把這些實(shí)現(xiàn)之后,其余需要擴(kuò)展的功能可以自行實(shí)現(xiàn),我這里也只是在業(yè)務(wù)中的擴(kuò)展,并非完善的。
于是,我們的表單組件就變成了這樣
<template> <div class="nx-form"> <el-form ref="form" v-bind="$attrs" :model="source" class="nx-form" > <el-row :gutter="20"> <el-col v-for="item in config" :key="item.key" :span="item.hidden ? 0 : item.span || 8" > <el-form-item v-if="!item.hidden" :label="item.label" :prop="item.key" :label-width="item.labelWidth || labelWidth || '120px'" v-bind="item.itemProps" > <slot v-if="item.component === 'slot'" :name="item.slotName"></slot> <div v-else-if="item.component === 'innerText'" :class="item.innerClass" :style="item.style" > {{ item.innerText || source[item.key] }} </div> <template v-else> <div class="nx-flex-align-center"> <component :is="item.component" v-model="source[item.key]" style="width: 100%;flex: 1;" v-bind="item.props" v-on="item.listeners" > <template v-if="item.component === 'el-radio-group'"> <el-radio v-for="(radio, radioIndex) in item.data" :key="radioIndex" style="margin-top: 10px;" :label="radio.value" :disabled="radio.disabled" > {{ radio.label }} </el-radio> </template> <template v-if="item.component === 'el-checkbox-group'"> <el-checkbox v-for="(checkbox, checkboxIndex) in item.data" :key="checkboxIndex" :label="checkbox.value" > {{ checkbox.label }} </el-checkbox> </template> <template v-if="item.component === 'el-select'"> <el-option v-for="(option, optionIndex) in item.data" :key="optionIndex" :label="option.label" :value="option.value" ></el-option> </template> </component> <div v-if="item.after" class="nx-form__after" > {{ item.after }} </div> </div> <div v-if="item.tips" class="nx-form__tips" v-html="item.tips" ></div> </template> </el-form-item> <!-- <div v-if="item.tips" :style="{ marginLeft: item.labelWidth || '120px' }" class="nx-form__tips" v-html="item.tips" ></div> --> </el-col> </el-row> </el-form> </div> </template> export default { name: 'NxForm', components: {}, props: { config: { type: Array, default: () => [] }, source: { type: Object, default: () => ({}) } }, methods: { resetFields() { this.$refs.form.resetFields(); }, clearValidate() { this.$refs.form.clearValidate(); }, async validate() { const valid = await this.$refs.form.validate(); return valid; } } };
可以看到,我擴(kuò)展了一個(gè)data
字段,用來作為el-select
el-checkbox-group
el-radio-group
的數(shù)據(jù)源,這些特殊的組件單獨(dú)列出就行了,基本上也之后有這么幾個(gè)。
methods
里也只是為了方便添加了一些常用的form
方法,基本不做邏輯處理。
現(xiàn)在看一下,這樣的配置可以生成怎樣的表單
注意:我這里定義了一部分全局樣式,比如在
schema form
下的組件,全部占滿整格,使其比較美觀。
生成這樣一個(gè)常用的篩選項(xiàng)表單
<template> <div> <nx-form ref="searchForm" :source="searchForm" :config="searchConfig" > <div slot="search"> <el-button type="primary" @click="$refs.nxTable.search(1)">查詢</el-button> <el-button @click="reset()">重置</el-button> </div> </nx-form> </div> </template> <script> export default { data() { searchForm: { keyWord: '', newsType: '', newsStatus: '', publishTime: [], createTime: [] }, }, computed: { searchConfig() { return [ { key: 'keyWord', component: 'el-input', span: 8, label: '關(guān)鍵字', props: { placeholder: '標(biāo)題/創(chuàng)建人', clearable: true } }, { key: 'newsType', component: 'el-select', span: 8, label: '類型:', props: { placeholder: '請選擇', clearable: true }, data: this.newsTypes }, { key: 'newsStatus', component: 'el-select', span: 8, label: '狀態(tài):', props: { placeholder: '請選擇', clearable: true }, data: statusTypes }, { key: 'publishTime', component: 'el-date-picker', label: '發(fā)布時(shí)間:', span: 8, props: { clearable: true, valueFormat: 'timestamp', type: 'datetimerange', defaultTime: ['00:00:00', '23:59:59'], rangeSeparator: '-', startPlaceholder: '請選擇開始時(shí)間', endPlaceholder: '請選擇結(jié)束時(shí)間' } }, { key: 'createTime', component: 'el-date-picker', label: '創(chuàng)建時(shí)間:', span: 8, props: { clearable: true, valueFormat: 'timestamp', type: 'datetimerange', defaultTime: ['00:00:00', '23:59:59'], rangeSeparator: '-', startPlaceholder: '請選擇開始時(shí)間', endPlaceholder: '請選擇結(jié)束時(shí)間' } }, { component: 'slot', slotName: 'search', span: 8, labelWidth: '0' } ]; } } } </script>
其余的找了一些,也沒啥特別的,就不貼了,簡單來說,這個(gè)百來行的組件,應(yīng)用在多個(gè)大型項(xiàng)目當(dāng)中,易用性,擴(kuò)展性,沒有出現(xiàn)什么問題,配合我們自定義的其他table
組件、dialog
組件,十分鐘就可以實(shí)現(xiàn)一個(gè)完整的B端增刪改查。
值得一提的是,為了表單的易用性,我們基本上所有的自定義組件都支持了使用v-model
做數(shù)據(jù)綁定,達(dá)到簡單易用的效果。
結(jié)語
代碼是找了一個(gè)很久的項(xiàng)目寫的一個(gè)思路,之后的項(xiàng)目中都有改進(jìn)優(yōu)化,大致只是分享一個(gè)思路,如果有什么想法的,歡迎指正。
到此這篇關(guān)于Vue2 Element Schema Form 配置式生成表單的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Vue2 Element Schema Form生成表單內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue2實(shí)現(xiàn)移動(dòng)端上傳、預(yù)覽、壓縮圖片解決拍照旋轉(zhuǎn)問題
這篇文章主要介紹了vue2實(shí)現(xiàn)移動(dòng)端上傳、預(yù)覽、壓縮圖片解決拍照旋轉(zhuǎn)問題,需要的朋友可以參考下2017-04-04Vue router錯(cuò)誤跳轉(zhuǎn)到首頁("/")的問題及解決
這篇文章主要介紹了Vue router錯(cuò)誤跳轉(zhuǎn)到首頁("/")的問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10vue 3 中watch 和watchEffect 的新用法
本篇文章主要通過 Options API 和 Composition API 對(duì)比 watch 的使用方法,讓大家快速掌握 vue3 中 watch 新用法,需要的朋友可以參考一下哦,希望對(duì)大家有所幫助2021-11-11vue-cli3+typescript新建一個(gè)項(xiàng)目的思路分析
這篇文章主要介紹了vue-cli3+typescript新建一個(gè)項(xiàng)目的思路,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08Vue-Ant Design Vue-普通及自定義校驗(yàn)實(shí)例
這篇文章主要介紹了Vue-Ant Design Vue-普通及自定義校驗(yàn)實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-10-10關(guān)于vue-router的beforeEach無限循環(huán)的問題解決
本篇文章主要介紹了關(guān)于vue-router的beforeEach無限循環(huán)的問題解決,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09vue3響應(yīng)式Proxy與Reflect的理解及基本使用實(shí)例詳解
這篇文章主要為大家介紹了vue3響應(yīng)式Proxy與Reflect的理解及基本使用實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08