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; } } }); }