问题

在使用 Element 时,碰到一个问题,就是:
树形控件获取选择的节点时,现有的逻辑是,选中父节点时所有的子节点会被选中(checked),但是当该节点下不是选中所有子节点的时候,主节点不会被选中,而是处于一种半选中状态,提交时通过 getCheckedKeys() 方法也不会提交父节点,因为半选中状态下 checked 属性是 false 的。

而我需要的,是提交子节点的同时,父节点也要提交。
element-ui-tree

解决方案

现有的解决方案

看了一下别人的解决方案,基本上都是那几种:

  1. 修改 element-ui 的源码,这种方法最不好
  2. 获取选中的节点,获取节点的父级
  3. getHalfCheckedKeys() 获取半选中状态的节点,然后用 concat 将半选中和选中的拼接

第三种方法是最顺滑的,但是还是有问题,如果是进入编辑状态,初始化选中节点后,父节点一勾上,子节点就全勾上了,所以,还需要遍历一下,把子节点判断一下,不该勾上的去掉。

我的实现方案

鉴于感觉还是有点麻烦,我用了另一种思路去实现这个问题,虽然性能没那么好,但是对于我的系统来说问题不大。

树形控件中,开启 check-strictly,在显示复选框的情况下,严格遵循父子不互相关联。即是说,勾选父节点和勾选子节点,没有任何的关系。这是为了解决默认选中节点加载时,选中父节点会同时选中所以子节点,这不是我们想要的。

<el-tree
    show-checkbox
    node-key="id"
    check-strictly
    @check-change="checkChange"
    ref="tree">
</el-tree>

然后使用 check-change 回调方法:

···
methods: {
    subjectCheckChange(data, ifCheck) {
        // 父节点操作
        if (data.parent_id !== 0) {
            if (ifCheck === true) {
                // 如果选中,设置父节点为选中
                this.$refs.tree.setChecked(data.parent_id, true)
            } else {
                // 如果取消选中,检查父节点是否该取消选中(可能仍有子节点为选中状态)
                var parentNode = this.$refs.tree.getNode(data.parent_id)
                var parentHasCheckedChild = false
                for (var i = 0, parentChildLen = parentNode.childNodes.length; i < parentChildLen; i++) {
                    if (parentNode.childNodes[i].checked === true) {
                        parentHasCheckedChild = true
                        break
                    }
                }
                if (!parentHasCheckedChild) this.$refs.tree.setChecked(data.parent_id, false)
            }
        }
    
        // 子节点操作
        // 如果取消选中,取消子节点选中
        if (data.children != null && ifCheck === false) {
            for (var j = 0, len = data.children.length; j < len; j++) {
                var childNode = this.$refs.tree.getNode(data.children[j].id)
                if (childNode.checked === true) {
                    this.$refs.tree.setChecked(childNode.data.id, false)
                }
            }
        }
    }
}
···

check-change 是节点选中状态发生变化时的回调,共三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点本身是否被选中、节点的子树中是否有被选中的节点。

其中第三个参数,不知道为何一直为 false,可能是个 Bug,所以我没用到。大体的是思路就是在选中状态发生改变时,改变父节点状态和子节点状态。