Vue2 Element Schema Form 配置式生成表單的實現(xiàn)
前置知識點
為了實現(xiàn)一個Schema Form配置式表單的生成,需要了解一部分前置知識點。
Component
vue 提供了一個內(nèi)置組件 Component,用來動態(tài)渲染組件,舉個例子,本篇文章以Element UI 為例,假設(shè)我們?nèi)肿粤?code>Element UI的組件,那么下面一段代碼
<Component is="el-input"></Component>
將被渲染為el-input組件。
好了,最重要的實現(xiàn)知識點已經(jīng)完了,只要了解了這一點,我這個Schema Form的實現(xiàn)思路,你就能完全看懂了,就這么簡單。
但是為了我們表單的易用性,我們再了解一點兒其他的。
比如Component組件并非只能接收一個字符串,渲染全局組件,同時可以接收一個Component組件,也就是說,當(dāng)我們Element UI 組件沒有全局注冊的時候,我們可以通過import { ElInput } from 'element',傳遞給Component組件,同樣可以完成渲染一個el-input組件的功能。
$attrs
第二個知識點,vue的屬性透傳,假如你有這么一個疑惑 —— 我對el-input進(jìn)行了二次封裝,那el-input接收的props我是否需要在二次封裝的組件中進(jìn)行props的定義,再逐一傳遞給el-input才能生效。
如果有這樣的疑惑那么$attrs可以幫你,對于二次封裝的組件,通過定義v-bind="$attrs",傳遞給父組件的屬性即可透傳給el-input,于是就有了這么一個疑問,$attrs可以綁定給v-bind,那么一個普通的對象可以嗎,答案是可以的。
這是我們 schema form 變得好用的第二個重要的知識點。
$listeners
與 $attrs 相同,做事件透傳的,通過v-on綁定。
以上就是我認(rèn)為,實現(xiàn)Schema Form配置式生成表單所需要掌握的全部知識及擴(kuò)展思考,接下來,我們簡單完成一個配置式表單.
表單的結(jié)構(gòu)是什么樣的
1、我可能希望對表單進(jìn)行一部分特殊的處理,所以,包一層div總是沒錯的,當(dāng)然,這是我的習(xí)慣,你們可以自行選擇。
2、既然是表單,那一定被el-form包裹。
3、為了配置式布局的需要,我希望引入el-row el-col柵格系統(tǒng)
4、無論如何完善表單,必然不可能滿足所有要求,那最簡單的方式就是拋出slot
5、有些時候我希望渲染文本呢?有些時候我希望渲染字段的值而不涉及任何組件呢?
6、最后才是渲染對應(yīng)的組件
那么,一個表單的結(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>
渲染對應(yīng)組件,但需要對某些組件特殊處理
</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 需要傳入一個數(shù)據(jù)源,這個數(shù)據(jù)源可以內(nèi)部定義再傳給外部,也可以傳入一個對象,利用對象的特性做雙向綁定,我選擇了后者
3、el-col項可能有時不顯示,所以config上擴(kuò)展一個字段hidden,用于控制該項是否顯示。
4、el-form-item的屬性透傳
5、innerText的樣式定義
一些特殊的描述出來了,其余的再贅述,那么,config的數(shù)據(jù)結(jié)構(gòu)就是這樣
{
key: '', // 當(dāng)前字段的 key 值,同時會傳到 el-form-item 的prop,不傳數(shù)據(jù)驗證和重置會失效
label: '', // 當(dāng)前 el-form-item 的label
hidden: '', // 當(dāng)前表單項是否展示
labelWidth: '', // el-form-item 的label寬度
component: '', // 支持 slot、innerText、Component,渲染成什么
slotName: '', // compoment 為 slot 時,該值為對應(yīng)slot的名字供外部使用
innerClass: '', // component 為 innerText 時,給文本的樣式,通常為全局樣式
innerStyle: '', // 同上
innerText: '', // component 為 innerText 時,優(yōu)先顯示的文本,否則會顯示當(dāng)前的字段值
itemProps: '', // 注入到 el-form-item 的屬性
props: '', // 當(dāng) component 為渲染組件時,注入到渲染組件當(dāng)中的屬性
listeners: '', // 當(dāng) component 為渲染組件時,注入到渲染組件當(dāng)中的事件
}
當(dāng)把這些實現(xiàn)之后,其余需要擴(kuò)展的功能可以自行實現(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ò)展了一個data字段,用來作為el-select el-checkbox-group el-radio-group的數(shù)據(jù)源,這些特殊的組件單獨列出就行了,基本上也之后有這么幾個。
methods里也只是為了方便添加了一些常用的form方法,基本不做邏輯處理。
現(xiàn)在看一下,這樣的配置可以生成怎樣的表單
注意:我這里定義了一部分全局樣式,比如在
schema form下的組件,全部占滿整格,使其比較美觀。

生成這樣一個常用的篩選項表單
<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ā)布時間:',
span: 8,
props: {
clearable: true,
valueFormat: 'timestamp',
type: 'datetimerange',
defaultTime: ['00:00:00', '23:59:59'],
rangeSeparator: '-',
startPlaceholder: '請選擇開始時間',
endPlaceholder: '請選擇結(jié)束時間'
}
},
{
key: 'createTime',
component: 'el-date-picker',
label: '創(chuàng)建時間:',
span: 8,
props: {
clearable: true,
valueFormat: 'timestamp',
type: 'datetimerange',
defaultTime: ['00:00:00', '23:59:59'],
rangeSeparator: '-',
startPlaceholder: '請選擇開始時間',
endPlaceholder: '請選擇結(jié)束時間'
}
},
{
component: 'slot',
slotName: 'search',
span: 8,
labelWidth: '0'
}
];
}
}
}
</script>
其余的找了一些,也沒啥特別的,就不貼了,簡單來說,這個百來行的組件,應(yīng)用在多個大型項目當(dāng)中,易用性,擴(kuò)展性,沒有出現(xiàn)什么問題,配合我們自定義的其他table組件、dialog組件,十分鐘就可以實現(xiàn)一個完整的B端增刪改查。
值得一提的是,為了表單的易用性,我們基本上所有的自定義組件都支持了使用v-model做數(shù)據(jù)綁定,達(dá)到簡單易用的效果。
結(jié)語
代碼是找了一個很久的項目寫的一個思路,之后的項目中都有改進(jìn)優(yōu)化,大致只是分享一個思路,如果有什么想法的,歡迎指正。
到此這篇關(guān)于Vue2 Element Schema Form 配置式生成表單的實現(xiàn)的文章就介紹到這了,更多相關(guān)Vue2 Element Schema Form生成表單內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于vue3+antDesign2+echarts?實現(xiàn)雷達(dá)圖效果
這篇文章主要介紹了基于vue3+antDesign2+echarts?實現(xiàn)雷達(dá)圖,本文通過實例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-08-08
vue3標(biāo)簽中的ref屬性詳解及如何使用$refs獲取元素
這篇文章主要給大家介紹了關(guān)于vue3標(biāo)簽中的ref屬性詳解及如何使用$refs獲取元素的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考借鑒價值,需要的朋友可以參考下2024-11-11
vue單頁面如何通過prerender-spa-plugin插件進(jìn)行SEO優(yōu)化
這篇文章主要介紹了vue單頁面如何通過prerender-spa-plugin插件進(jìn)行SEO優(yōu)化,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05
Composition API思想封裝NProgress示例詳解
這篇文章主要為大家介紹了Composition API思想封裝NProgress示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
前端實現(xiàn)pdf預(yù)覽功能的全過程(基于vue)
這篇文章主要給大家介紹了關(guān)于前端實現(xiàn)pdf預(yù)覽功能的相關(guān)資料,前端實現(xiàn)預(yù)覽最好的效果還是PDF,不會出現(xiàn)一些文字錯亂和亂碼的問題,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09

