分享一个自己写的antdv
动态表单组件
<!-- 动态表单组件 -->
<template>
<div>
<div v-for="(item, index) in value" :key="item[rowKey] || index">
<a-row>
<a-col :span="24">
<slot :item="item">
<a-row v-if="column.length" v-bind="flex">
<a-col
:span="24 / column.length - 1"
v-for="(columnItem, columnIndex) in column"
:key="item.title || columnIndex"
>
<a-form-model-item :label="showLabel && columnItem.label" v-bind="showLabel && formItemLayout">
<div v-if="!isPreview">
<a-select
v-if="columnItem.select"
v-model="item[columnItem.title]"
:options="columnItem.select"
:placeholder="columnItem.placeholder"
@change="selectChange($event, index, columnItem)"
@blur="blur"
allow-clear
show-search
/>
<a-tooltip v-else>
<template slot="title"> {{ item[columnItem.title] || columnItem.placeholder }} </template>
<a-input
@blur="blur"
v-model="item[columnItem.title]"
:placeholder="columnItem.placeholder"
allow-clear
/>
</a-tooltip>
</div>
<div v-else>
<div v-if="columnItem.select">
{{ (columnItem.select.find(({ value }) => value == item[columnItem.title]) || {}).label }}
</div>
<div v-else>{{ item[columnItem.title] }}</div>
</div>
</a-form-model-item>
</a-col>
</a-row>
</slot>
</a-col>
<div v-if="!isPreview" class="item-btns">
<a-button class="item-btn" shape="circle" icon="minus" @click="delItem(index)" />
<a-button class="item-btn" shape="circle" icon="plus" @click="addItem(index)" />
</div>
</a-row>
</div>
</div>
</template>
<script>
export default {
data() {
return {
flex: {
type: 'flex',
justify: 'space-between',
},
}
},
props: {
/**
* 指定vue中的key,建议指定为id
*/
rowKey: {
type: String,
default: () => '_key',
},
/**
* 指定动态表单表头和列
*/
column: {
type: Array,
default: () => [
{ title: 'name', label: 'name', placeholder: 'Please input name' },
{ title: 'value', label: 'value', placeholder: 'Please input value' },
],
},
/**
* 显示label
*/
showLabel: {
type: Boolean,
default: () => false,
},
/**
* 是否预览模式
*/
isPreview: {
type: Boolean,
default: () => false,
},
/**
* 数据,非受控组件可用v-model或者value绑定,传入的数据会随着用户操作而更新
*/
value: {
type: Array,
default: () => [],
},
/**
* 表单元素布局式样
*/
formItemLayout: {
type: Object,
default: () => ({
labelCol: { span: 6 },
wrapperCol: { span: 18 },
colon: false,
}),
},
/**
* 表单blur事件
*/
blur: {
type: Function,
default: () => () => {},
},
},
mounted() {
if (!this.value || !this.value.length) {
this.$emit('input', [this.genItem(Math.random())])
}
},
computed: {
/**
* 获取过滤后的items
*/
getItems() {
return this.value.filter((item) =>
this.column.some(({ title }) => item[title] != null && item[title] != undefined && item[title] != '')
)
},
},
methods: {
addItem(index) {
let item = this.genItem()
let itemList
if (index != null && index != undefined) {
itemList = [...this.value]
itemList.splice(index 1, 0, item)
} else {
itemList = [...this.value, item]
}
this.$emit('input', itemList)
this.$emit('addItem', index)
},
delItem(index) {
let itemList = [...this.value]
if (itemList.length == 1) {
let item = {
...itemList[index],
...Object.fromEntries(this.column.map(({ title }) => [title, undefined])),
}
itemList.splice(index, 1, item)
} else {
itemList.splice(index, 1)
this.$emit('delItem', index)
}
this.$emit('input', itemList)
},
selectChange(value, index, column) {
let list = [...this.value]
let item = { ...list[index], [column.title]: value }
list.splice(index, 1, item)
this.$emit('input', list)
column.change && column.change(value, index)
},
genItem(key) {
return Object.fromEntries(
[...this.column, { title: this.rowKey, value: key || Math.random() }].map(({ title, value }) => [
title,
value || undefined,
])
)
},
watchValue() {
this.$emit('change', this.getItems)
},
},
watch: {
value: {
deep: true,
handler: 'watchValue',
},
},
}
</script>
<style lang="stylus" scoped>
.item-btns {
display: flex;
margin-top: 4px;
.item-btn {
margin-left: 10px;
}
}
</style>
使用方式:
代码语言:javascript复制<dynamic-form-item
:blur="() => $refs.storyTheme.onFieldBlur()"
:is-preview="!isEditProduction"
v-model="formData.storyTheme"
:column="[
{
label: '标签',
title: 'tag',
select: [
{ value: '0', label: '门派' },
{ value: '1', label: '武侠' },
{ value: '2', label: '玄幻' },
],
placeholder: '请选择标签',
},
{ label: '补充说明', title: 'desc', placeholder: '请填入补充说明' },
]"
></dynamic-form-item>
效果:
支持动态增减表单行