el-form-renderer使用教程
前言
el-form-renderer是基于element的表單渲染器,動態(tài)渲染,數(shù)據(jù)驅(qū)動
el-form-renderer/README-zh.md at dev · FEMessage/el-form-renderer · GitHub
el-form-renderer是基于 element-ui 封裝的表單渲染器,但不局限于 element-ui 組件。在完整繼承了 element 的form表單屬性的基礎(chǔ)上進行了簡單擴展,一些非表單組件或者封裝的自定義組件,如圖片上傳、富文本等也可進行整合,從而用戶能夠通過使用一段預(yù)設(shè)的數(shù)據(jù)渲染出一個完整的表單。

起步
?# Step1 確認(rèn)你已經(jīng)正確安裝并使用了 element-ui yarn add @femessage/el-form-renderer
<template>
<el-form-renderer :content="content"></el-form-renderer>
</template>
<script>
import ElFormRenderer from '@femessage/el-form-renderer'
export default {
components: {
ElFormRenderer,
},
data() {
return {
content: [],
}
},
}
</script>使用
支持 el-form 上的所有屬性。
- content:[ObjectArray] 定義表單的內(nèi)容,每一個 Object 代表一個原子表單 el-input, el-select, ...,一切 el-form-item 上的屬性都在此聲明,而對于 el-input 等之上的屬性在 $el 屬性上進行聲明,該 Object 上還存在其他屬性,例如: id, type,label, options可選的,等。還有hidden定義其是否隱藏等屬性
- id: id: string 每一個原子都存在 id,用于存儲該原子的值,不能重復(fù)
- type: string 可以是element提供的所有表單組件類型,如傳入'input',則渲染出'el-input,當(dāng)type="group"時使用 items內(nèi)依然遵循同一層級的id不重復(fù)的原則
- readonly 只讀的 當(dāng) type === 'input' 時展示文本值, 當(dāng) type === 'select' 時展示對應(yīng)。 label 對于其他組件等同于 disabled = true
- default: 默認(rèn)值
- options ({label: string; value?: any}[])具有選擇功能的原子表單可用此定義可選項 select, radio-group, radio-button, checkbox-group, checkbox-button
- hidden 傳入一個方法,并返回 boolean,返回 true 時則隱藏該表單項 * formValue 為當(dāng)前 form 值,item 為當(dāng)前表單項的定義
- el 用于定義具體原子表單(如el-input)的屬性,比如定義el-input的placeholder
- component component適用于渲染局部注冊組件和自定義組件,而type適用于帶el-前綴的全局組件
- label 設(shè)置el表單項的標(biāo)簽
update-form && getFormValue
- update-form 更新表單方法 默認(rèn)情況下,updateForm 來者不拒,不在表單設(shè)置內(nèi)的值,也可以存儲進去
- getFormValue 默認(rèn)情況下,通過 updateForm 設(shè)置的所有值都會輸出。 如果只想輸出根據(jù) content 設(shè)置的表單項的值,可傳入 {strict: true}
<template>
<div class="update-form">
<el-form-renderer :content="content" inline ref="formRender">
<el-button @click="setValue">更新表單</el-button>
<div>
<el-button type="primary" @click="getValue(false)">獲取數(shù)據(jù)</el-button>
<el-button type="primary" @click="getValue(true)"
>獲取數(shù)據(jù)過濾掉字段</el-button
>
</div>
</el-form-renderer>
<pre>{{ value }}</pre>
</div>
</template>
<script>
export default {
name: "update-form",
data() {
return {
value: {},
content: [
{
id: "name",
type: "input",
label: "name",
el: {
placeholder: "name",
},
},
{
id: "area",
type: "select",
label: "area",
el: {
placeholder: "area",
},
options: [
{
label: "shanghai",
value: "shanghai",
},
{
label: "beijing",
value: "beijing",
},
],
},
],
};
},
methods: {
getValue(strict) {
const value = this.$refs.formRender.getFormValue({ strict });
this.value = value;
},
setValue() {
this.$refs.formRender.updateForm({
name: "alvin",
area: "shanghai",
// 設(shè)置冗余字段
extraKey: "extraValue",
});
},
},
};
</script>表單項動態(tài)顯示或隱藏(hidden)
以通過 hidden 控制某一表單項的顯示或隱藏。
<template>
<div>
<el-form-renderer :content="content"></el-form-renderer>
</div>
</template>
<script>
import ElFormRenderer from "@femessage/el-form-renderer";
export default {
components: {
ElFormRenderer,
},
data() {
return {
content: [
{
type: "select",
id: "selected",
label: "選擇項目",
options: [
{
label: "項目A",
value: "optionA",
},
{
label: "項目B",
value: "optionB",
},
],
},
{
label: "資料",
type: "input",
id: "data",
el: {
placeholder: "項目B的具體內(nèi)容",
},
hidden: (form, item) => {
return this.hiddenChange(form, item);
},
},
],
};
},
methods: {
hiddenChange(form, item) {
console.log(form); //form 收集的數(shù)據(jù)
console.log(item); //觸發(fā)元素
return form.selected !== "optionB";
},
},
};
</script>表單數(shù)據(jù)聯(lián)動(on)
可以通過 on 來監(jiān)聽 blur , focus 等事件來實現(xiàn)表單聯(lián)動 監(jiān)聽表單項發(fā)出的事件
<template>
<div>
<el-form-renderer :content="content"></el-form-renderer>
</div>
</template>
<script>
import ElFormRenderer from "@femessage/el-form-renderer";
export default {
components: {
ElFormRenderer,
},
data() {
return {
content: [
{
label: "英文名",
type: "input",
id: "fullName",
on: {
blur: ([event], updateForm) => {
const value = event.target.value;
const lastName = value.split(" ")[1]; // 通過空格分割出內(nèi)容
updateForm({ lastName }); // 更新其他表單項
},
},
},
{
label: "姓氏",
type: "input",
id: "lastName",
},
],
};
},
};
</script>輸入/輸出格式化(inputFormat/outputFormat)
拿 日期范圍選擇器 為例,組件輸出的值是一條字符串,但后端接口格式是兩個字段 {startDate, endDate},則此時需要對數(shù)據(jù)進行格式化處理
inputFormat 轉(zhuǎn)換輸入的數(shù)據(jù), 使其變成表單項需要的數(shù)據(jù)格式
<template>
<el-form-renderer :content="content" ref="form" />
</template>
<script>
export default {
data() {
return {
content: [
{
el: {
type: 'daterange',
placeholder: '選擇日期',
valueFormat: 'yyyy-MM-dd'
},
type: 'date-picker',
id: 'date',
label: '日期',
// 接口設(shè)計的時間范圍是兩個字段 '2019-07-23','2019-07-24'
// 處理后的值為 [ '2019-07-23', '2019-07-24' ]
inputFormat: row => ([row.startDate, row.endDate])
}
]
}
}
}
</script>outputFormat 轉(zhuǎn)換輸出的數(shù)據(jù), 使其變成需要的(接口期望的)數(shù)據(jù)格式
<script>
export default {
data() {
return {
content: [
{
el: {
type: 'daterange',
placeholder: '選擇日期',
valueFormat: 'yyyy-MM-dd'
},
type: 'date-picker',
id: 'date',
label: '日期',
// 處理前的值為 date: [ '2019-07-23', '2019-07-24' ]
// 處理后的值為 {startDate: '2019-07-23', endDate: '2019-07-24'}
outputFormat: val => {
if (!val) {
return {startDate: '', endDate: ''}
}
return {
startDate: val[0],
endDate: val[1]
}
}
}
]
}
}
}
</script>set-options
使用setOptions更新選擇選項
<template>
<el-form-renderer ref="form" :content="content" inline>
<el-button @click="setOptions">更新options</el-button>
</el-form-renderer>
</template>
<script>
export default {
name: "select-demo",
data() {
return {
content: [
{
id: "area",
type: "select",
label: "select",
el: {
placeholder: "select",
},
options: [
{
label: "shanghai",
value: "shanghai",
},
{
label: "beijing",
value: "beijing",
},
],
},
],
};
},
methods: {
setOptions() {
this.$refs.form.setOptions("area", [
{
label: "guangzhou",
value: "guangzhou",
},
{
label: "hangzhou",
value: "hangzhou",
},
]);
},
},
};
</script>el-form-renderer 實踐案例
案例一
A 系統(tǒng)有一個解析簡歷的功能,后端接口只能解析電話、郵箱,也即接口只返回 phone、email 兩個字段。后來接口更新了,支持解析姓名:
后端:簡歷解析接口更新了,現(xiàn)在會返回多一個字段 name,你前端那邊也更新一下吧。 前端:您隨便加,接口直接更新就行了,前端不用改。 后端:這么神奇的嗎?這是怎么做到的?

那么前端是如何做到接口返回多一個字段,自己卻不用修改代碼的呢?
分析
原因在于使用了 el-form-renderer 使用了 updateForm 來更新表單值。 updateForm 方法接受一個對象,只要傳入對象的 key 與表單的 id 對應(yīng)上即可更新數(shù)據(jù)。代碼片段如下:
<template>
<el-form-renderer :content="content" ref="form" />
</template>
<script>
export default {
data() {
return {
content: [
{
type: 'input',
id: 'name',
label: '名稱'
},
{
type: 'input',
id: 'phone',
label: '電話'
},
{
type: 'input',
id: 'email',
label: '郵箱'
},
// ...
],
}
},
methods: {
async fetch() {
const data = await fetchData() // data: Object
// data 中返回多了一個字段 name,也不需要修改代碼
this.$refs.form.updateForm(data)
}
}
}
</script>所以,即使后端豐富了這個 data ,前端也可以“照吃不誤”
如果直接使用 el-form 則無法完成這種操作:你需要手動去更新每個與 el-form-item 綁定的 data 值
<template>
<el-form ref="form" :model="form">
<el-form-item label="名稱">
<el-input v-model="form.name"></el-input>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
form: {
// 每一個表單項需要主動綁定
name: '',
phone: '',
email: '',
},
}
},
methods: {
async fetch() {
const {name} = await fetchData() // data: Object
this.form.phone = data.phone
this.form.email = data.email
// data 中返回多了一個字段 name,需要多寫下面一行代碼
this.form.name = name
}
}
}
</script>案例二
場景
B 系統(tǒng)的表單頁面比較多,其中不乏帶有復(fù)雜組件的表單,如下圖紅框片所示:

直接使用 el-form 開擼,整個頁面耦合在一起代碼超過 1000 行。
使用 el-form-renderer 后,通過拆分組件,整個頁面代碼量在 300 行左右,業(yè)務(wù)組件代碼量在 100~300 行之間。
明顯能感覺到頁面簡潔了許多,維護性大大提高。
那么,el-rorm-renderer 是怎么做到精簡主頁面代碼的呢?
分析
秘訣在于 el-form-renderer 支持通過 component 屬性渲染自定義組件、在組件內(nèi)部定義檢驗規(guī)則,提高了拆分頁面的可能性。
下面代碼示例中,把選擇優(yōu)惠券的表格,抽離成了一個單獨的組件。
<!--表單主頁面-->
<template>
<el-form-renderer :content="content" ref="form" />
</template>
<script>
import SelectTableList from './select-table-list.vue'
export default {
data() {
return {
content: [
// ...
{
id: 'selectedCoupon',
// 渲染自定義 table 組件
component: SelectTableList,
label: '選擇優(yōu)惠券'
},
// ...
],
}
}
}
</script>下面是自定義 table 組件示例代碼。
<!--自定義 table 組件示例代碼-->
<template>
<div class="select-table-list">
<el-button type="primary" size="small" @click="visible = true">選擇</el-button>
<el-table :data="selectedList" border></el-table>
<!--
省略一些代碼
-->
</div>
</template>
<script>
export default {
name: 'select-table-list',
// 自定義校驗規(guī)則
rules: [
{
required: true,
message: '自定義組件的提醒消息'
}
],
props: ['value'],
data() {
return {
visible: false,
selectedList: []
}
},
methods: {
confirm() {
const selectedVal = 'table選中的值'
// 更新 value 值,這樣 el-form-renderer 可以通過 getFormValue() 拿到該值
this.$emit('input', selectedVal)
this.visible = false
}
}
}
</script>自定義組件接入指南
el-form-renderer 的 type 有限, 默認(rèn)只能渲染普通的表單項, 假如現(xiàn)在要渲染一個上傳組件, type 就不夠用了, 那怎么辦呢? 這時候 component 選項就派上用場了
本文將介紹如何開發(fā)符合 el-form-renderer 接入標(biāo)準(zhǔn)的自定義組件, 實現(xiàn)對自定義組件的渲染
自定義組件接入的關(guān)鍵是在組件內(nèi)部實現(xiàn) v-model
建議在自定義組件上綁定 $attrs 和 $listeners
el-form-renderer 對 v-model 的要求是:
有一個 props 為 value對外觸發(fā) input 事件
<template>
<el-form-renderer :content="content" />
</template>
<script>
import MyInput from "@/components/my-input.vue";
export default {
data() {
return {
content: [
{
component: MyInput,
id: "myInput",
label: "label",
// 傳入組件屬性
el: {
placeholder: "請輸入一個 title",
// type: "submit", // submit button
title: "這是一個標(biāo)題", // custom defined props
},
// 傳入組件事件
on: {
focus: ([event], updateForm) => {
console.log(event.target.value); // output: input value
},
customEvent: ([value, msg], updateForm) => {
console.log(msg); // output: 'message'
},
},
},
{
id: "document",
type: "input",
el: {
type: "textarea",
},
},
],
};
},
};
</script><template>
<div>
<!-- 自定義組件 my-input -->
<el-input
:value="value"
@input="onInput"
v-bind="$attrs"
v-on="$listeners"
/>
</div>
</template>
<script>
export default {
props: {
value: String,
title: String,
},
watch: {
value(value) {
this.$emit("customEvent", value, "message");
},
},
methods: {
onInput(val) {
this.$emit("input", "my-input: " + val);
},
},
};
</script>需要注意,on 中的 function 定義,組件 emit 事件的 payload 將以「數(shù)組」的方式,回調(diào)到第一個參數(shù)
第二個參數(shù)為 updateForm 方法
到此這篇關(guān)于el-form-renderer使用教程的文章就介紹到這了,更多相關(guān)el-form-renderer使用 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VUE?Element修改el-input和el-select長度的具體步驟
這篇文章主要給大家介紹了關(guān)于VUE?Element修改el-input和el-select長度的具體步驟,文中通過代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-12-12
三步搞定:Vue.js調(diào)用Android原生操作
這篇文章主要介紹了三步搞定:Vue.js調(diào)用Android原生操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09
Vue 實現(xiàn)分頁與輸入框關(guān)鍵字篩選功能
這篇文章主要介紹了Vue 實現(xiàn)分頁+輸入框關(guān)鍵字篩選功能,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2020-01-01
vue?parseHTML?函數(shù)拿到返回值后的處理源碼解析
這篇文章主要為大家介紹了vue?parseHTML?函數(shù)拿到返回值后的處理源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-07-07
vue自定v-model實現(xiàn)表單數(shù)據(jù)雙向綁定問題
vue.js的一大功能便是實現(xiàn)數(shù)據(jù)的雙向綁定。這篇文章主要介紹了vue自定v-model實現(xiàn) 表單數(shù)據(jù)雙向綁定的相關(guān)知識,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-09-09

