vue動態渲染表單配置項
在項目中,我們經常會用到各種表單,但是數量一般都不多,那當我們編寫大量表單時怎么辦呢,難道我們還要一個標簽一個標簽的寫嗎?如果各個表單之間又出現了各種級聯關系各種判斷呢?所以這時候就出現了另外一種方式,我們可以通過對象的方式編寫表單項來替換element本來的標簽寫法,以使我們能夠方便清晰的最大化的控制每個表單。
當我們編寫一個普通的input表單時,我們一般會直接在template里這樣寫:
<el-input v-model="inputValue" placeholder="請輸入"></el-input>
用了表單配置項后,我們可以這樣在data里寫:
{
type: 'input',
key: 'inputValue',
label: 'input框:',
placeholder: '請輸入'
}
我們先不討論怎么就可以這樣寫了,我們先來明白為什么要這樣用
- 可以通過this.XXX來改變某個表單項
- 不用再在標簽里加各種判斷
- 標簽寫法太死板
- render寫法,更貼近vue底層
如何配置
input舉栗,最后會附上其他的表單項
// 準備一個文件---itemRenders.js
export default {
name: 'ItemRender',
props: {
// 類型,input or select or ...
type: String,
// 主要配置項
config: Object
},
// 渲染函數
render: function (h) {
switch (this.type) {
case 'input':
return inputItem(h, this.config);
default:
return '';
}
}
};
function inputItem(h, config) {
let {
key, // 綁定的值
props, // 屬性, 如disable等
listeners, // 事件,如onblur等
placeholder,
areaProps // 額外屬性如type等
} = config;
let on = listeners || {};
let pps = props || {};
let area = areaProps || {};
return h('el-input', {
props: {
...pps,
value: key,
disabled: pps.disabled
},
attrs: {
placeholder: placeholder || pps.placeholder || '請輸入',
...area
},
on: {
...on,
// 實現雙向綁定
input: (val) => {
key = val;
}
}
});
}
如何使用
在.vue文件中使用itemRenders.js
<template>
<div>
<item-render
:type="item.type"
:config="{
placeholder: item.placeholder || '',
...item.config,
key: item.key
}"
>
</item-render>
</div>
</template>
<script>
import ItemRender from './itemRenders';
export default {
components: { 'item-render': ItemRender },
data() {
return {
item: {
type: 'input',
key: 'inputValue',
label: 'input框:',
placeholder: '請輸入',
config: {
props: {
disabled: true
},
listeners: {
blur: _this.blur1
}
}
}
}
}
}
</script>
這只是渲染一個input的寫法,但既然會用到這種寫法,那就代表要渲染的表單數量可能有點大,像我們項目中有些頁面新增時表單項多達100+,所以,如果頁面只用到個位數的表單的情況,這里還是建議親親直接使用ele提供的標簽寫法。
渲染大量表單
那渲染大量表單時要怎么配置呢?
其實也很簡單,套個form就行了(主要以提交form表單為主)
我們可以先來準備個form表單組件,用的時候只需引入該組件即可
// formRender.vue
<template>
<el-form
ref="formRender"
:model="model"
:rules="rules"
>
<div class="block">
<el-form-item
v-for="item in items"
:key="item.key"
:label="item.label"
:prop="item.key"
>
<item-render
:type="item.type"
:config="{
placeholder: item.placeholder || '',
...item.config,
model,
key: item.key
}"
>
</item-render>
</el-form-item>
</div>
</el-form>
</template>
<script>
import ItemRender from './itemRenders';
export default {
components: { 'item-render': ItemRender },
props: {
model: {
type: Object,
default: () => {}
},
// 規則
rules: {
type: Object,
default: () => {}
},
items: {
type: Array,
default: () => []
}
},
}
</script>
項目中使用
<template>
<FormRender
ref="formRender"
:model="form"
:rules="basicRules"
:items="items1"
></FormRender>
</template>
<script>
import FormRender from './formRender';
export default {
components: {FormRender},
data() {
return {
form: {
formItem1: '',
formItem2: [],
formItem3: ''
},
items1: [
// 輸入框
{
type: 'input',
key: 'formItem1',
label: 'formItem1:',
placeholder: '請輸入',
},
// 下拉框
{
type: 'select',
key: 'formItem2',
label: 'formItem2:',
placeholder: '請選擇',
config: {
props: {
filterable: true,
clearable: true,
disabled: false
},
options: () => _this.formItem2s,
optionConfig: {
label: 'name',
value: 'code'
},
listeners: {
change: _this.handleChange
}
}
}
],
basicRules: {
formItem1: [ { required: true, trigger: 'blur' }]
},
formItem2s: []
}
}
}
</script>
其余表單配置項
這里只提供部分常用的給大家做參考,大家也可以從別的角度去考慮,適合我們的并不一定適合所有人
-
下拉選擇框
function selectItem(h, config) { let { model, key, props, listeners, options, optionConfig, placeholder, syncConfig } = config; let opl = 'label'; let opv = 'value'; if (optionConfig) { if (optionConfig.label) { opl = optionConfig.label; } if (optionConfig.value) { opv = optionConfig.value; } } let opts = options(); let ops = []; if (opts) { ops = opts.map((option) => { return h('el-option', { key: option[opv], props: { label: option[opl] || option['text'], value: option[opv], disabled: option.disabled } }); }); } let on = listeners || {}; let pps = props || {}; if (syncConfig) { pps = { ...pps, ...syncConfig() }; } return h( 'el-select', { props: { placeholder, ...pps, value: model[key] }, on: { ...on, change: (val) => { model[key] = val; if (on.change) { on.change(val); } } } }, ops ); }
-
日期選擇器
function dateItem(h, config) { let { model, key, props, listeners, placeholder, type } = config; let pps = props || {}; let on = listeners || {}; return h('el-date-picker', { props: { ...pps, value: model[key] }, attrs: { placeholder: placeholder || pps.placeholder || '請輸入', type: type || 'date' }, on: { ...on, input: (val) => { model[key] = val; } } }); }
-
計數器
function inputNumberItem(h, config) { let { model, key, props } = config; let pps = props || {}; return h('el-input-number', { props: { ...pps, value: model[key] }, on: { change: (val) => { model[key] = val; } } }); }
-
上傳
function uploadItem(h, config) { let { model, key, props, btnProps, listeners, iconProps } = config; let pps = props || {}; let btnProp = btnProps || {}; let iconProp = iconProps || {}; let on = listeners || {}; return h( 'el-upload', { props: { ...pps, 'file-list': model[key] }, class: { upload_demo: true }, on: { ...on } }, [ h( 'el-button', { props: { ...btnProp, size: btnProp.size || 'small' } }, [ h('svg-icon', { style: iconProp.styles, props: { iconClass: iconProp.iconClass } }), '上傳' ] ) ] ); }
-
級聯選擇器
function cascaderItem(h, config) { let { model, key, props, listeners, options, optionProps } = config; let ops = options(); let on = listeners || {}; let pps = props || {}; return h('el-cascader', { props: { value: model[key], ...pps, options: ops, props: optionProps }, on: { change: (val) => { model[key] = val; if (on.change) { on.change(val); } } } }); }
-
時間選擇器
function timePicker(h, config) { let { model, key, props, listeners, placeholder, type, syncConfig } = config; let pps = props || {}; if (syncConfig) { pps = { ...pps, ...syncConfig() }; } let on = listeners || {}; return h('el-time-picker', { props: { ...pps, value: model[key] }, attrs: { placeholder: placeholder || pps.placeholder || '請輸入', type: type || 'date' }, on: { ...on, input: (val) => { model[key] = val; } } }); }