在工作中经常会遇到可编辑表格加校验功能,这里根据我遇到的问题分享给大家解决方案,踩了很多坑,希望对你有帮助的话能点个赞。
注意:如果表格数据是一次性拿到的,那么需要arrIndex来帮助确定当前行,(我就是这种情况)
如果数据是通过分页接口请求拿到的,那么涉及到arrIndex属性的地方都可以删除arrIndex
效果图:当点击确定的时候进行表单校验,禁用状态的学科组单元格不进行校验,
当选择的教研室类型不是国家级教研室,则禁用学科组并清除该行校验效果。
<a-form :model="vroomList" ref="formRef" :rules="rules">
<a-table ref="tableRef" :pagination="pagination" :dataSource="vroomList" :columns="columns">
<template #headerCell="{title,column}">
<div class="custom-table-title">
<span v-if="isShowRequiredIcon(column.dataIndex)" class="required-icon">*</span>
<span class="title">{{title}}</span>
</div>
</template>
<template #bodyCell="{ column, record,index }">
<!-- 教研室名称 -->
<template v-if="column.dataIndex === 'name'">
<!-- 如果你的表格数据是接口请求拿到的,并且分页也是通过请求,那么name用这种写法:name="[index,'name']",
其他校验同理 -->
<a-form-item :name="[arrIndex+index,'name']" :rules="rules.name">
<a-input v-model:value="record.name" placeholder="请输入教研室名称" allowClear/>
</a-form-item>
</template>
<!-- 教研室类型 -->
<template v-if="column.dataIndex === 'vroomType'">
<a-form-item :name="[arrIndex+index,'vroomType']" :rules="rules.vroomType">
<a-select
v-model:value="record.vroomType"
:options="vroomTypeList"
:field-names="{ label: 'name' , value: 'code' }"
@change="vroomTypeChange($event,record,arrIndex+index)"
placeholder="请选择教研室类型"
:allow-clear="true"
/>
</a-form-item>
</template>
<!-- 学科组 -->
<template v-if="column.dataIndex === 'subjectGroupId'">
<a-form-item :name="[arrIndex+index,'subjectGroupId']"
:rules="[{validator: (rule,value)=>validateSubjectGroup(rule,value,record), trigger: 'change' }]">
<a-select
<!-- 我这里是联动校验,当选择的教研室不是国家级,则会禁用学科组并且清除该行学科组的校验 -->
:disabled="record.isDisabledSubjectGroup"
v-model:value="record.subjectGroupId"
:options="subjectGroupList"
:field-names="{label:'subjectGroupName',value:'subjectGroupId'}"
placeholder="请选择学科协作组"
/>
</a-form-item>
</template>
<template v-if="column.dataIndex==='action'">
<div>
<a-popconfirm title="确定要删除吗?" @confirm=delTap(record.customKey)>
<a>删除</a>
</a-popconfirm>
</div>
</template>
</template>
</a-table>
</a-form>
<script lang="ts">
// 导入各种包、组件啥的
const columns = [
{
title: "教研室名称",
dataIndex: "name",
align: "center",
width: 300,
fixed:"left"
},
{
title: "教研室类型",
dataIndex: "vroomType",
align: "center",
width: 280
},
{
title: "学科组",
dataIndex: "subjectGroupId",
width: 240
},
{
title: "操作",
dataIndex: "action",
align: "center",
width: 100,
fixed:"right"
},
];
export default defineComponent({
name: "EditVrooms",
components: {},
props:{
vroomList:{
type:array,
default:()=>[]
}
},
emits:[],
setup(props,{emit}) {
const state = reactive({
vroomList: [], // 表格数据
vroomTypeList:[], // 教研室分类
subjectGroupList: [], // 学科协作组
arrIndex: 0, // 数组索引,用于确定页码的当前行
注意:这里如果表格数据(vroomList)是接口请求拿到的,可以不用这个变量,上面模板绑定的name也不用这个变量,
如果数据是外部传进来的(一次性拿到的数据),这个变量必须要,因为在分页的时候第一页的index和其他页的index是一样的,
arrIndex用来确定是第几页第几行
})
// 自定义校验学科组,当禁用的时候不校验,返回成功的promise
const validateSubjectGroup = (rule,value,record) => {
if(value || record.isDisabledSubjectGroup){
return Promise.resolve()
}
return Promise.reject("请选择学科组")
}
const rules = {
name: [{ required: true, message: '请输入教研室名称' }],
vroomType: [{ required: true, message: '请选择教研室类型' }],
subjectGroupId: [{ required: true, validator:validateSubjectGroup, message: '请选择学科组' }],
};
// 这里是分页的配置项,如果你的数据是一次性拿到的,那么这里需要配置,如果是通过分页接口请求拿到的,
那么这里的onChange函数就需要改成调用接口请求的逻辑,并且涉及到arrIndex 属性的代码都可以删除
const pagination = reactive({
current: 1, // 初始页码
pageSize: 10,
showSizeChanger: false,
total:state.localVroomList.length,
showTotal:()=> `共 ${state.localVroomList.length} 条`,
onChange:(current,pageSize)=>{
pagination.current = current
state.arrIndex = (current-1) * pageSize
}
})
// 这里用来控制表格标题是否显示必填 * 图标
const showRequiredList = ["action"]
const isShowRequiredIcon = (dataIndex) => {
return !showRequiredList.includes(dataIndex)
}
// 我这里的vroomList是一次性拿到的数据,需要计算总页数,如果你全选最后一页删除,组件会自动减少一页,
但是注意:pagination的current不会-1,所以下面的方法主动调用了一下来计算当前是第几页,主要目的是为了更新arrIndex,
保证编辑行更改数据或者校验不会出问题。
// 如果你的分页数据是通过接口请求,那么这里和下面的更新方法都可以删除
const totalPages = computed(()=> {
return Math.ceil(state.vroomList.length / pagination.pageSize);
})
// 处理当删除最后一页时current不会更新问题,这会导致校验行不对
const updateCurrentPageIndex = () => {
if (pagination.current > totalPages.value) {
pagination.current = totalPages.value;
}
pagination.onChange(pagination.current,pagination.pageSize)
}
// 选择教研室类型
const vroomTypeChange = (vroomType,record,index) => {
record.subjectGroupId = null
// 这里选择的不是国家级教研室则给当前行学科组添加一个禁用标识
record.isDisabledSubjectGroup = !(vroomType === VroomTypeEnum.NationalLevel)
if(!(vroomType === VroomTypeEnum.NationalLevel)){
// 这个地方必须这样写,用[[]]双数组,否则其他写法都不生效
formRef.value.clearValidate([[(state.arrIndex+index),"subjectGroupId"]]);
}
}
// 获取导入列表
const getList = () => {
state.vroomList= cloneDeep(props.vroomList)
state.vroomList.forEach((item,index)=>{
item.isDisabledSubjectGroup = item.vroomType !== VroomTypeEnum.NationalLevel
item.customKey = "key" + index
})
}
onMounted(()=>{
getList()
getSubjectGroupList() // 学科组
getVroomTypeList() // 教研室类型
})
return {
rules,
...toRefs(state),
formRef,
columns,
pagination,
isShowRequiredIcon,
vroomTypeChange,
validateSubjectGroup
};
},
});
</script>