动态表格
框架(Vue2) 组件(ant-design-vue 1.7)
背景:
在实习期间,参与过很多的后台管理项目,有着这样的需求:实现表格的动态添加,且需要每一项都要能进行编辑与删除作用,且还需进行校验。
具体大概需求如下
实现手段
总体实现起来难度不是很大,本质上是使用框架table
中的template
<template slot="name" scope="text,record">
/* record 就是一行的数据 只需要将每一行数据和对应的input进行双向绑定 */
/* slot所对应即是columns上的数据dataIndex */
<a-input v-model="record.name" />
</template>
同理也能实现其他的表单形式
<template slot="name" scope="text,record">
/* record 就是一行的数据 只需要将每一行数据和对应的input进行双向绑定 */
/* slot所对应即是columns上的数据dataIndex */
<a-select style="width: 100%" v-model="record.degree">
<a-select-option v-for="item in selectList" :key="item.value" :value="item.value">
{{item.label}}
</a-select-option>
</a-select>
</template>
现在实现数据上处理后 就要实现数据的增删操作 增加一行的操作直接在对应数据数组添加新一行的数据
<template slot="footer">
<div style="padding: 5px;text-align: center;border: 1px solid blue" @click="addRow()">新增数据</div>
</template>
<script>
/* 需要每一行数据的独一性 */
import { v4 } from 'uuid'
data() {
return {
initModel: {}
validateModel: {},
}
}
addRow() {
/* initModel 是我定义的初始化数据的对象 */
/* 需要注意一点 现只是浅拷贝 如果initModel存在多层结构 可能造成所有数据都是公用同一个对象 */
this.model.push({ id: v4(), ...this.initModel })
},
</script>
至于删除操作等同于新增 就不一一写代码了(还是找到需要删除的行 在原数据数组进行修改就好
校验
先只能对每一行的数据都设置一个validate对象来控制当行数据 的某一项是不是满足要求的。
/* 在每个tmeplate设置一个动态的class 负责该数据错误时的显示 */
<template slot="name" scope="text,record">
<a-input :class="{'has-error': record.validate.name }" v-model="record.name"/>
</template>
<script>
data() {
return {
initModel: {}
validateModel: {},
}
}
/* 在提交时候进行所有数据校验 */
submit() {
let val = true
this.model.forEach(ele => {
/* 当validate为false 不会去判断后面的 */
val = validateObj(ele) && val
})
if (val) {
alert('表单数据正常')
}
},
/* 增加validate对象 */
addRow() {
this.model.push({ id: v4(), ...this.initModel, validate: { ...this.validateModel } })
},
</script>
具体逻辑校验 先阶段只是对数据设置必填的做法(具体改动可根据具体业务
/**
* 动态表格 校验数据
*
* @param {Object} obj
* @returns 该表单值是否违反提交情况
*/
const validateObj = (obj) => {
if (obj === null || obj === {}) {
return
}
let res = true
for (const key in obj.validate) {
if (obj[key] === undefined || obj[key] === '' || obj[key] === null) {
obj.validate[key] = true
res = false
}
else {
obj.validate[key] = false
}
}
return res
}
显示效果: 正确会显示为:
优化手段
现阶段很多逻辑都是学死 然后当然能通过配置项形式进行抽离 但基本的逻辑处理上大概如此 而且在表单的校验上不能像form组件一样直接在下面进行错误显示(比较可惜的地方)
样例代码
<template>
<div class="dyamic-table">
<div class="title">
<h1>动态表格:</h1>
<a-button @click="submit">校验</a-button>
</div>
<div class="content">
<a-table
bordered
:scoll="1088"
:data-source="model"
:columns="columns"
rowKey="id"
>
<template slot="name" scope="text,record">
<a-input :class="{'has-error': record.validate.name }" placeholder="请输入姓名" v-model="record.name"></a-input>
</template>
<template slot="age" scope="text, record">
<a-input :class="{'has-error': record.validate.age }" placeholder="请输入年龄" v-model="record.age"></a-input>
</template>
<template slot="degree" scope="text, record">
<a-select :class="{'has-error': record.validate.degree }" placeholder="请选择" style="width: 100%" v-model="record.degree">
<a-select-option v-for="item in selectList" :key="item.value" :value="item.value">{{item.label}}</a-select-option>
</a-select>
</template>
<template slot="action" scope="text, record">
<div style="display: flex; justify-content: space-around;">
<a @click="delRow(record)">删除</a>
</div>
</template>
<template slot="footer">
<div style="padding: 5px;text-align: center;border: 1px solid blue" @click="addRow()">新增数据</div>
</template>
</a-table>
</div>
</div>
</template>
<script>
import { v4 } from 'uuid'
import validateObj from '../helper.js'
export default {
data() {
return {
selectList: [
{
value: 0,
label: '小学'
},
{
value: 1,
label: '初中'
},
{
value: 2,
label: '高中'
},
{
value: 3,
label: '大学'
},
{
value: 4,
label: '研究生'
},
{
value: 5,
label: '博士'
}
],
model: [],
initModel: {
name: undefined,
age: undefined,
degree: undefined
},
validateModel: {
name: false,
age: false,
degree: false
},
columns: [
{
title: '姓名',
dataIndex: 'name',
align: 'center',
width: '200',
scopedSlots: { customRender: 'name' }
},
{
title: '年龄',
dataIndex: 'age',
align: 'center',
scopedSlots: { customRender: 'age' }
},
{
title: '学历',
palceholder: '请选择',
width: '150',
align: 'center',
dataIndex: 'degree',
scopedSlots: { customRender: 'degree' }
},
{
title: '操作',
dataIndex: 'action',
align: 'right',
scopedSlots: { customRender: 'action' }
}
]
}
},
methods: {
submit() {
let val = true
this.model.forEach(ele => {
/* 当validate为false 不会去判断后面的 */
val = validateObj(ele) && val
})
if (val) {
alert('表单数据正常')
}
},
addRow() {
this.model.push({ id: v4(), ...this.initModel, validate: { ...this.validateModel } })
},
delRow({ id }) {
this.model = this.model.filter(ele => ele.id !== id)
}
}
}
</script>
<style lang="less" >
.dyamic-table {
padding: 50px;
width: 77%;
.ant-table-footer {
background: #fff;
}
.title {
display: flex;
justify-content: space-between;
}
.has-error {
border-color: #f5222d;
}
}
</style>
其他常用组件 github也可以看看支持一下的:后台组件