el-form-renderer使用教程
前言
el-form-renderer是基于element的表單渲染器,動(dòng)態(tài)渲染,數(shù)據(jù)驅(qū)動(dòng)
el-form-renderer/README-zh.md at dev · FEMessage/el-form-renderer · GitHub
el-form-renderer是基于 element-ui 封裝的表單渲染器,但不局限于 element-ui 組件。在完整繼承了 element 的form表單屬性的基礎(chǔ)上進(jìn)行了簡單擴(kuò)展,一些非表單組件或者封裝的自定義組件,如圖片上傳、富文本等也可進(jìn)行整合,從而用戶能夠通過使用一段預(yù)設(shè)的數(shù)據(jù)渲染出一個(gè)完整的表單。
起步
?# 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)容,每一個(gè) Object 代表一個(gè)原子表單 el-input, el-select, ...,一切 el-form-item 上的屬性都在此聲明,而對(duì)于 el-input 等之上的屬性在 $el 屬性上進(jìn)行聲明,該 Object 上還存在其他屬性,例如: id, type,label, options可選的,等。還有hidden定義其是否隱藏等屬性
- id: id: string 每一個(gè)原子都存在 id,用于存儲(chǔ)該原子的值,不能重復(fù)
- type: string 可以是element提供的所有表單組件類型,如傳入'input',則渲染出'el-input,當(dāng)type="group"時(shí)使用 items內(nèi)依然遵循同一層級(jí)的id不重復(fù)的原則
- readonly 只讀的 當(dāng) type === 'input' 時(shí)展示文本值, 當(dāng) type === 'select' 時(shí)展示對(duì)應(yīng)。 label 對(duì)于其他組件等同于 disabled = true
- default: 默認(rèn)值
- options ({label: string; value?: any}[])具有選擇功能的原子表單可用此定義可選項(xiàng) select, radio-group, radio-button, checkbox-group, checkbox-button
- hidden 傳入一個(gè)方法,并返回 boolean,返回 true 時(shí)則隱藏該表單項(xiàng) * formValue 為當(dāng)前 form 值,item 為當(dāng)前表單項(xiàng)的定義
- el 用于定義具體原子表單(如el-input)的屬性,比如定義el-input的placeholder
- component component適用于渲染局部注冊(cè)組件和自定義組件,而type適用于帶el-前綴的全局組件
- label 設(shè)置el表單項(xiàng)的標(biāo)簽
update-form && getFormValue
- update-form 更新表單方法 默認(rèn)情況下,updateForm 來者不拒,不在表單設(shè)置內(nèi)的值,也可以存儲(chǔ)進(jìn)去
- getFormValue 默認(rèn)情況下,通過 updateForm 設(shè)置的所有值都會(huì)輸出。 如果只想輸出根據(jù) content 設(shè)置的表單項(xiàng)的值,可傳入 {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>
表單項(xiàng)動(dòng)態(tài)顯示或隱藏(hidden)
以通過 hidden
控制某一表單項(xiàng)的顯示或隱藏。
<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: "選擇項(xiàng)目", options: [ { label: "項(xiàng)目A", value: "optionA", }, { label: "項(xiàng)目B", value: "optionB", }, ], }, { label: "資料", type: "input", id: "data", el: { placeholder: "項(xiàng)目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)動(dòng)(on)
可以通過 on 來監(jiān)聽 blur , focus 等事件來實(shí)現(xiàn)表單聯(lián)動(dòng) 監(jiān)聽表單項(xiàng)發(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 }); // 更新其他表單項(xiàng) }, }, }, { label: "姓氏", type: "input", id: "lastName", }, ], }; }, }; </script>
輸入/輸出格式化(inputFormat/outputFormat)
拿 日期范圍選擇器 為例,組件輸出的值是一條字符串,但后端接口格式是兩個(gè)字段 {startDate, endDate},則此時(shí)需要對(duì)數(shù)據(jù)進(jìn)行格式化處理
inputFormat 轉(zhuǎn)換輸入的數(shù)據(jù), 使其變成表單項(xiàng)需要的數(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è)計(jì)的時(shí)間范圍是兩個(gè)字段 '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更新選擇選項(xiàng)
<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 實(shí)踐案例
案例一
A 系統(tǒng)有一個(gè)解析簡歷的功能,后端接口只能解析電話、郵箱,也即接口只返回 phone、email 兩個(gè)字段。后來接口更新了,支持解析姓名:
后端:簡歷解析接口更新了,現(xiàn)在會(huì)返回多一個(gè)字段 name,你前端那邊也更新一下吧。 前端:您隨便加,接口直接更新就行了,前端不用改。 后端:這么神奇的嗎?這是怎么做到的?
那么前端是如何做到接口返回多一個(gè)字段,自己卻不用修改代碼的呢?
分析
原因在于使用了 el-form-renderer 使用了 updateForm 來更新表單值。 updateForm 方法接受一個(gè)對(duì)象,只要傳入對(duì)象的 key 與表單的 id 對(duì)應(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 中返回多了一個(gè)字段 name,也不需要修改代碼 this.$refs.form.updateForm(data) } } } </script>
所以,即使后端豐富了這個(gè) data ,前端也可以“照吃不誤”
如果直接使用 el-form 則無法完成這種操作:你需要手動(dòng)去更新每個(gè)與 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: { // 每一個(gè)表單項(xiàng)需要主動(dòng)綁定 name: '', phone: '', email: '', }, } }, methods: { async fetch() { const {name} = await fetchData() // data: Object this.form.phone = data.phone this.form.email = data.email // data 中返回多了一個(gè)字段 name,需要多寫下面一行代碼 this.form.name = name } } } </script>
案例二
場(chǎng)景
B 系統(tǒng)的表單頁面比較多,其中不乏帶有復(fù)雜組件的表單,如下圖紅框片所示:
直接使用 el-form 開擼,整個(gè)頁面耦合在一起代碼超過 1000 行。
使用 el-form-renderer 后,通過拆分組件,整個(gè)頁面代碼量在 300 行左右,業(yè)務(wù)組件代碼量在 100~300 行之間。
明顯能感覺到頁面簡潔了許多,維護(hù)性大大提高。
那么,el-rorm-renderer 是怎么做到精簡主頁面代碼的呢?
分析
秘訣在于 el-form-renderer 支持通過 component 屬性渲染自定義組件、在組件內(nèi)部定義檢驗(yàn)規(guī)則,提高了拆分頁面的可能性。
下面代碼示例中,把選擇優(yōu)惠券的表格,抽離成了一個(gè)單獨(dú)的組件。
<!--表單主頁面--> <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', // 自定義校驗(yàn)規(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àng), 假如現(xiàn)在要渲染一個(gè)上傳組件, type
就不夠用了, 那怎么辦呢? 這時(shí)候 component 選項(xiàng)就派上用場(chǎng)了
本文將介紹如何開發(fā)符合 el-form-renderer 接入標(biāo)準(zhǔn)的自定義組件, 實(shí)現(xiàn)對(duì)自定義組件的渲染
自定義組件接入的關(guān)鍵是在組件內(nèi)部實(shí)現(xiàn) v-model
建議在自定義組件上綁定 $attrs 和 $listeners
el-form-renderer 對(duì) v-model 的要求是:
有一個(gè) props 為 value對(duì)外觸發(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: "請(qǐng)輸入一個(gè) title", // type: "submit", // submit button title: "這是一個(gè)標(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)到第一個(gè)參數(shù)
第二個(gè)參數(shù)為 updateForm 方法
到此這篇關(guān)于el-form-renderer使用教程的文章就介紹到這了,更多相關(guān)el-form-renderer使用 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Vue ElementUI之Form表單驗(yàn)證遇到的問題
- element修改form的el-input寬度,el-select寬度的方法實(shí)現(xiàn)
- vue+element-ui集成隨機(jī)驗(yàn)證碼+用戶名+密碼的form表單驗(yàn)證功能
- vue elementui el-form rules動(dòng)態(tài)驗(yàn)證的實(shí)例代碼詳解
- vue用elementui寫form表單時(shí),在label里添加空格操作
- 關(guān)于vue中element-ui?form或table?lable換行的問題
- vue+ElementUI 關(guān)閉對(duì)話框清空驗(yàn)證,清除form表單的操作
相關(guān)文章
詳解Vue中是如何實(shí)現(xiàn)cache緩存的
這篇文章分享一個(gè)比較有意思的東西,那就是Vue中如何實(shí)現(xiàn)cache緩存的,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-07-07VUE?Element修改el-input和el-select長度的具體步驟
這篇文章主要給大家介紹了關(guān)于VUE?Element修改el-input和el-select長度的具體步驟,文中通過代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-12-12三步搞定:Vue.js調(diào)用Android原生操作
這篇文章主要介紹了三步搞定:Vue.js調(diào)用Android原生操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09Vue 實(shí)現(xiàn)分頁與輸入框關(guān)鍵字篩選功能
這篇文章主要介紹了Vue 實(shí)現(xiàn)分頁+輸入框關(guān)鍵字篩選功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01vue?parseHTML?函數(shù)拿到返回值后的處理源碼解析
這篇文章主要為大家介紹了vue?parseHTML?函數(shù)拿到返回值后的處理源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07vue動(dòng)態(tài)組件之:is在組件中的使用場(chǎng)景
這篇文章主要介紹了vue動(dòng)態(tài)組件之:is在組件中的使用場(chǎng)景,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07vue自定v-model實(shí)現(xiàn)表單數(shù)據(jù)雙向綁定問題
vue.js的一大功能便是實(shí)現(xiàn)數(shù)據(jù)的雙向綁定。這篇文章主要介紹了vue自定v-model實(shí)現(xiàn) 表單數(shù)據(jù)雙向綁定的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-09-09