赞
踩
本文根据平常业务开发中经常接触的有操作权限的可编辑表格需求,给出Vue中另一种实现可编辑表格的方式,即分离数据与其私有属性的解耦方式,下文将以ElementUi为例。
/** * @description: 实现可编辑表格(分离数据 与 行为状态) * @param {Map} propMap 存储表格row和状态数据的键值对 * @param {Array} refArr 存储Map中的value值,将其变为响应式(若是在vue3中使用,则无需refArr) * @param {Function} createRowState 自定义编辑状态 * @return {Object} */ function useEditTable (propMap, refArr, createRowState) { let oldTable = []; let oldProps = []; // 求差集 const getDiffSet = (bigSet, smallSet) => bigSet.filter(item => !smallSet.includes(item)) // 增 const addRowState = (addArr, curProps) => { addArr.forEach(item => { const rowState = createRowState(curProps, {}); propMap.set(item, rowState); refArr.push(rowState); }) } // 删 const delRowState = (delArr) => { delArr.forEach(item => { const rowState = propMap.get(item); const index = refArr.findIndex(it => it === rowState); propMap.delete(item); refArr.splice(index, 1); }) } // 改 const modRowState = (addArr, delArr, curProps) => { addArr.forEach((item, index) => { const preItem = delArr[index]; const preRowState = propMap.get(preItem); const curRowState = createRowState(curProps, preRowState); propMap.set(item, curRowState).delete(preItem); }) } // 设置行对应的状态属性 const setRowState = (newTable, curProps) => { if (!curProps.length) return; // 取差值 const diffLen = newTable.length - oldTable.length; if (diffLen > 0) { // add addRowState(getDiffSet(newTable, oldTable), curProps); } else if (diffLen < 0) { // del delRowState(getDiffSet(oldTable, newTable)); } else { // mod modRowState(getDiffSet(newTable, oldTable), getDiffSet(oldTable, newTable), curProps); } // 缓存 oldProps = [...curProps]; oldTable = [...newTable]; } // 更新单个属性的状态 const updatePropState = (curProps) => { // propMap为空时(表格从纯展示到可编辑状态) if (!propMap.size) addRowState(oldTable, curProps); // 更新属性状态 const addProps = getDiffSet(curProps, oldProps); const delProps = getDiffSet(oldProps, curProps); if (!addProps.length && !delProps.length) return; for (const rowState of propMap.values()) { // 创建单个状态属性 createRowState(addProps, rowState); // 删除单个状态属性(置空) delProps.forEach(prop => rowState[prop] = null); } // 缓存当前的可编辑属性列表 oldProps = [...curProps]; } return { setRowState, updatePropState } }
<template> <div class="hello"> <el-form :model="{ tb: tableData }" ref="validForm" size="mini"> <el-table :data="tableData" border style="width: 100%" @cell-click="cellClick"> <el-table-column type="index" width="50"></el-table-column> <el-table-column v-for="{ prop, label } in columns" :key="prop" :prop="prop" :label="label" v-slot="{ row, $index }" > <!-- 表格为纯展示状态时 --> <span v-if="!isEdit">{{ row[prop] }}</span> <!-- 表格为可编辑状态时,由cell-click事件切换sppan和表单项 --> <el-form-item v-else :prop="`tb.${$index}.${prop}`" :rules="getRule()"> <span v-if="!getPropState(row, prop, 'edit')">{{ row[prop] }}</span> <el-input v-else v-model="row[prop]" @blur="handleBlur(row, prop)"></el-input> </el-form-item> </el-table-column> </el-table> </el-form> <el-button @click="changeEditProps">change editProps<el-button> </div> </template>
<script> import { useEditTable , columns, tableData } from "./static.js"; export default { name: "EditTable", data() { return { columns, tableData: [], editProps: ["a", "b", "c", "d", "e"], // 默认编辑的属性名 isEdit: false, // 判断属性的编辑状态是否初始化完成 propMap: new Map(), refArr: [], }; }, created() { // 若表格为可编辑状态 this.isEdit = true; // 注册可编辑表格通用函数 this.editTable = useEditTable(this.propMap, this.refArr, this.createRowState); }, watch: { // 监听表格数据变化,同步状态 tableData(newTable) { /* setTimeout(() => { this.editTable.setRowState(newTable, this.editProps); if (!this.isEdit) this.isEdit = true; }, 50);*/ this.editTable.setRowState(newTable, this.editProps); }, // 当编辑属性动态变化时,对应的状态数据也同步新增或删除 editProps(newProps) { this.editProps.updatePropState(newProps); }, }, mounted() { this.renderTable(); }, methods: { // 自定义可编辑属性状态,在rowState中自定义对应的状态属性,并返回row createRowState(editProps, rowState) { editProps.forEach((prop) => { rowState[prop] = { edit: false, showCorner: false, }; }); return rowState; }, // 自定义获取单个属性状态集合或状态值 getPropState(row, prop, opType) { return opType ? this.propMap.get(row)?.[prop]?.[opType] : this.propMap.get(row)?.[prop]; }, // 自定义设置单个属性状态 setPropState(row, prop, opType, val) { this.propMap.get(row)[prop][opType] = val; }, // 点击单元格时,设置对应编辑状态的edit属性为true,即切换到表单项 cellClick(row, { property }) { if (!this.editProps.includes(property)) return; this.setPropState(row, property, "edit", true); }, // 模拟接口渲染 renderTable() { setTimeout(() => { this.tableData = tableData; }, 2000); }, // handleBlur(row, prop) { this.setPropState(row, prop, "edit", false); }, changeEditProps() { this.editProps = ['a', 'c']; }, getRule() { return [{ required: true, message: "必填", trigger: "blur" }]; }, }, }; </script>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。