1、封装 Form.vue:
<template>
<el-form
v-bind="$attrs"
v-on="$listeners"
:model="data"
ref="form"
@submit.native.prevent>
<el-form-item
v-for="(item,index) in items"
:key="index"
v-bind="getFormItemBind(item)"
v-on="getFormItemOn(item)">
<template v-if="$scopedSlots[item.prop]">
<slot
:name='item.prop'
:item='item'
:data="data" />
</template>
<component
v-else
v-model="data[item.prop]"
v-bind="getBind(item)"
v-on="getOn(item)"
:is="item.type"
/>
</el-form-item>
<!-- 拓展插槽,适合添加查询新增按钮 -->
<slot
:items="items"
:data="data" />
</el-form>
</template>
<script>
import * as _ from 'lodash'
let isObject = data => Object.prototype.toString.call(data) === '[object Object]'
let isFunction = data => Object.prototype.toString.call(data) === '[object Function]'
let config = {
getFormItemBind:item => ({
rules: (item.required && item.label) ? { required: true, message: "请输入"+item.label } : null,
...item,
label: item?.label ? item?.label+':' : '',
}),
getDefBind(item) {
return (
{
'el-input': {
placeholder: "请输入" + item.label,
},
'el-date-picker': {
placeholder: "请选择" + item.label,
valueFormat: "yyyy-MM-dd HH:mm:ss",
type: "datetime",
},
'el-input-number': {
placeholder: "请输入" + item.label,
},
'el-select': {
placeholder: "请选择" + item.label,
},
'el-switch': {
activeValue: true,
inactiveValue: false,
activeText: "是",
inactiveText: "否",
},
}[item.type] || {}
);
},
}
export default{
config,
props:{
value:Object,
items:Array,
},
computed:{
data:{
get(){
return this.value
},
set(value){
this.$emit('input',value)
}
}
},
methods:{
//----------普通方法-----------
resetFields(){
this.$refs.form.resetFields()
},
clearValidate(){
this.$refs.form.clearValidate()
},
validate(callback){
this.$refs.form.validate(callback)
},
getFormItemBind(item){
return config.getFormItemBind(item)
},
getFormItemOn(item){
return isObject(item.formItemOn)
? item.formItemOn
: isFunction(item.formItemOn)
? item.formItemOn(item, this.value)
: {}
},
getBind(item) {
let defBind = config.getDefBind(item),
bind = isObject(item.bind)
? item.bind
: isFunction(item.bind)
? item.bind(this.value, item, this.row)
: {};
return _.merge(defBind, bind);
},
getOn(item) {
return isObject(item.on)
? item.on
: isFunction(item.on)
? item.on(this.value, item, this.row)
: {};
},
//----------点击事件-----------
//----------接口方法-----------
}
}
</script>
<style lang="scss">
</style>
2、用法:
<template>
<div>
<EForm v-model="data" :items="items" label-width="100px">
<EBtn @click="_c_look">提交</EBtn>
</EForm>
</div>
</template>
<script>
export default {
data() {
let _this = this
return {
data:{
file:[{
name: "埃菲尔铁塔.png",
url: "/data/file/2022/05/26/117608f0-3d73-42ff-8df0-353a8ca2b5fc.png"
}],
images:[{
name: "埃菲尔铁塔.png",
url: "/data/file/2022/05/26/117608f0-3d73-42ff-8df0-353a8ca2b5fc.png"
}],
},
items: [
{
prop: "name",
label: "案例名称",
type: "el-input",
required: true,
},
{
prop: "start_time",
label: "发生时间",
type: "el-date-picker",
bind: {
type: "datetime",
placeholder: "请选择发生时间",
},
},
{
prop: "text",
label: "描述",
type: "el-input",
bind: {
type: "textarea",
autosize: { minRows: 2 },
},
},
{
prop: 'type',
label: '类型',
type: 'ESelect', // 这是自己封装的组件名称
bind:{
valueKey: 'id',
list: _this.$store.state.typeList,
optionBind:val => ({
label: val.name + '自定义',
value: val
})
}
},
{
prop: 'file',
label: '文件',
type: 'EUploadFile', // 这是自己封装的组件名称
bind:{
action: '/api/api/v1/file/upload',
getFile(res){
return {
name: res.file_path[0].originname,
url: res.file_path[0].storagepath,
}
},
}
},
{
prop: 'images',
label: '图片',
type: 'EUploadPicture',
bind:{
action: '/api/api/v1/file/upload',
getFile(res){
return {
name: res.file_path[0].originname,
url: res.file_path[0].storagepath,
}
},
}
},
{
prop: 'switch',
label: '开关',
type: 'el-switch'
}
],
}
},
mounted() {},
watch:{
'$store.state.typeList'(n, o){
this.items[3].bind.list = n
}
},
methods: {
_c_look(){
console.log(this.data);
}
},
};
</script>
<style></style>
3、效果: