vue element-table-tree-edit使用记录

614 阅读1分钟

最近接到一个任务,需求对tree数据结构进行动态编辑,看到这个需求时立马跑步前进到element-ui官网看有没有类似的例子:

image.png perfect! 那就开始淦! 先上代码:

<el-form
    :model="modalForm"
    :rules="modalForm.modalRules"
    ref="modalForm"
    class="edit-tree-table"
>
    <el-table
        empty-text="暂无"
        :data="modalForm.tableData"
        row-key="rowkey"
        default-expand-all
        :tree-props="{
            children: 'child',
            hasChildren: 'hasChildren',
        }"
        border
        :show-summary="true"
        :summary-method="summaryMethod"
    >
        <el-table-column>
            <template slot="header">
                <div>
                    <span class="warning">*</span
                    >序号
                </div>
            </template>
            <template slot-scope="scope">
                {{ scope.row.customIndex }}
            </template>
        </el-table-column>
        <el-table-column>
            <template slot="header">
                <div>
                    <span class="warning">*</span>
                    标题1
                </div>
            </template>
            <template slot-scope="scope">
                <el-form-item
                    :rules="
                        modalForm.modalRules.xxx
                    "
                >
                    <el-input
                        v-model="scope.row.xxx"
                        placeholder="请输入"
                    />
                </el-form-item>
            </template>
        </el-table-column>
        ...
        ...
        ...
    </el-table>
</el-form>

data() {
        return {
            modalForm: {
                tableData: [], // 存储表格table信息
                modalRules: {
                    xxx: [
                        {
                            required: true,
                            message: "请输入",
                            trigger: "blur",
                        },
                    ],
                },
            },
        };
    },

效果如下: image.png

这时候问题来了,当去编辑提交的时候,需要对表单进行校验,因为tree结构不知道有多少层级,el-form-item标签的prop 表单域该怎么写呢,通过代码测试发现

:prop="tableData.0.xxx"

:prop="tableData.0.child.0.xxx"

:prop="tableData.0.child.0.child.0.xxx"

...

...

这种方式是可以校验的。 于是在表格渲染的时候就直接为每个row去添加一个propKey就行。

想到了广度优先遍历, js如下:

// 广度优先遍历,以1,1.1,1.1.1的规则形式对树形列表生成确定唯一值的索引
setIndexDep(data) {
    let queue = [...data];
    let loop = 0;
    while (queue.length > 0) {
        loop++;
        [...queue].forEach((child, i) => {
            queue.shift();
            if (loop == 1) {
                child.currentIndex = i;
                child.customIndex = i + 1 + "";
                child.propKey = i + "";
            }
            if (child.child && child.child.length > 0) {
                child.dataType = 1;
                for (let ci = 0; ci < child.child.length; ci++) {
                    child.child[ci].currentIndex = ci;
                    child.child[ci].disabled = false;
                    child.child[ci].customIndex =
                        child.customIndex + "." + (ci + 1);
                    child.child[ci].propKey =
                        child.propKey + ".child." + ci;
                }
                queue.push(...child.child);
            } else {
                child.dataType = 2;
            }
        });
    }
    return data;
},

html如下:

<el-form
    :model="modalForm"
    :rules="modalForm.modalRules"
    ref="modalForm"
    class="edit-tree-table"
>
    <el-table
        empty-text="暂无"
        :data="modalForm.tableData"
        row-key="rowkey"
        default-expand-all
        :tree-props="{
            children: 'child',
            hasChildren: 'hasChildren',
        }"
        border
        :show-summary="true"
        :summary-method="summaryMethod"
    >
        <el-table-column>
            <template slot="header">
                <div>
                    <span class="warning">*</span
                    >序号
                </div>
            </template>
            <template slot-scope="scope">
                {{ scope.row.customIndex }}
            </template>
        </el-table-column>
        <el-table-column>
            <template slot="header">
                <div>
                    <span class="warning">*</span>
                    标题1
                </div>
            </template>
            <template slot-scope="scope">
                <el-form-item
                    :rules="
                        modalForm.modalRules.xxx
                    "
                    :prop="`tableData.${scope.row.propKey}.xxx`"
                >
                    <el-input
                        v-model="scope.row.xxx"
                        placeholder="请输入"
                    />
                </el-form-item>
            </template>
        </el-table-column>
        ...
        ...
        ...
    </el-table>
</el-form>

效果如下:

image.png 万事大吉!

以为这就结束了,这时候需求又加了,当输入某个值时候需要动态去根据规则去改变tree上row的一个值,用递归方法可以实现,后面想到一个代码少的方法就是一样用广度优先遍历先预埋一个propAttrKey,然后根据事件去拿到propAttrKey改变对应的值,代码如下:

setIndexDep(data) {
    let queue = [...data];
    let loop = 0;
    while (queue.length > 0) {
        loop++;
        [...queue].forEach((child, i) => {
            queue.shift();
            if (loop == 1) {
                child.currentIndex = i;
                child.customIndex = i + 1 + "";
                child.propKey = i + "";
                child.propAttrKey = "[" + i + "]" + "";
            }
            if (child.child && child.child.length > 0) {
                child.dataType = 1;
                for (let ci = 0; ci < child.child.length; ci++) {
                    child.child[ci].currentIndex = ci;
                    child.child[ci].disabled = false;
                    child.child[ci].customIndex =
                        child.customIndex + "." + (ci + 1);
                    child.child[ci].propKey =
                        child.propKey + ".child." + ci;
                    child.child[ci].propAttrKey =
                        child.propAttrKey + ".child" + "[" + ci + "]";
                }
                queue.push(...child.child);
            } else {
                child.dataType = 2;
            }
        });
    }
    return data;
},

eventFun(row) {
    let str = `this.modalForm.tableData${row.propAttrKey}`;
    this.$set(
        eval(str),
        "key",
        "value"
    );
},

后面校验又加了校验规则,需要下级之和等于上级,这种就是递归去校验了,分享下方法:

depFun(tree, node, rootNum) {
    if (tree[0].customIndex === node.customIndex) {
        // 根节点
        ...
        ...
        ...
        // 根节点判定
        return tree;
    }
    const dep = (source, customIndex) => {
        // 开启递归
        for (let i = 0; i < source.length; i++) {
            const item = source[i];
            if (item.customIndex === customIndex) {
                let sameLevelTotal = 0; // 同级之和
                source.forEach((v) => {
                    let num = v.xxx;
                    if (!num) {
                        num = 0;
                    } else {
                        num = parseInt(num);
                    }
                    sameLevelTotal += num;
                });
                console.log("当前节点:", item);
                console.log("同级:", source);
                console.log("父节点:", tree[0]);
                console.log("同级之和sameLevelTotal:", sameLevelTotal);
                console.log("父节点值:", tree[0].xxx);
                // 根据规则去校验
                if (item.xxx > this.totalNum) {
                    // 当前节点分不大于总分
                    item.xxxx = "";
                    item.xxxxx = "";
                    this.$message({
                        message: "提示xxx",
                        type: "warning",
                    });
                } else if (sameLevelTotal > tree[0].xxx) {
                    // 同级总分不应大于上级
                    item.xxxx = "";
                    item.xxxxx = "";
                    this.$message({
                        message: "提示xxx",
                        type: "warning",
                    });
                }
                ...
                ...
                ...
                return;
            }
            if (item.child) {
                // 只对非末端节点进行递归
                searchId(item.child, customIndex);
            }
        }
    };
    dep(tree[0].child, node.customIndex);
    return tree;
},

备注:文章只用于记录平常code中所碰到问题,无其他用途!