Bootstrap

Element中Tree树结构组件中实现Ctrl和Shift多选

直接上图

<el-tree
    :data="treeData"
    @node-click="handleNodeClick"
    :default-expand-all="true"
    :highlight-current="true"
    node-key="id"
    :expand-on-click-node="true"
    ref="treeRef"
></el-tree>
// node点击事件
const handleNodeClick = async (data, node) => {
    let event_ = window.event || arguments.callee.caller.arguments[0];
    let shiftKeyDowned = event_.shiftKey;
    let ctrlKeyDowned = event_.ctrlKey;
    if (ctrlKeyDowned == false && shiftKeyDowned == false) {
        // 都没有点击
        treeRef.value.setCheckedKeys([data.id]);
        batchSelectTree.value = [data];
    } else if (ctrlKeyDowned == true && shiftKeyDowned == false) {
        //只点击ctrl
        if (node.checked) {
            treeRef.value.setChecked(data.id, false);
            let index = batchSelectTree.value
                .map((el) => el.id)
                .indexOf(data.id);
            batchSelectTree.value.splice(index, 1);
        } else {
            treeRef.value.setChecked(data.id, true);
            batchSelectTree.value.push(data);
        }
    } else if (ctrlKeyDowned == false && shiftKeyDowned == true) {
        //只点击shift
        /**
         * 思路:通过计算开始索引到结束索引的差值,计算这段区间里有多少个数据,
         * 并且取数组第一个作为开始索引,往数组里push,每次shift,清空数据,因开始索引不会变化,只需要计算结束的索引即可。
         * 1.需要先判断一开始有没有选中一个。(以下情况,都是选中了一个的情况)
         * 2.往上选择,每次清空,从下往上把数据push到数组里,for --
         * 3.往下选择,每次清空,从上往下把数据push到数组里,for ++
         * 原始思路(但不完整实现):
         * 也是通过计算开始索引到结束索引的差值,计算这段区间里有多少个数据,
         * 但是是取数组最后一个作为开始索引,记录上次的开始索引和结束索引,插入到数组时是用unshift
         * 与vscode 的shift多选的差异:
         * 因每次shift都会清空上一次的选择,没有实现ctrl和shift交替使用,目前只支持同一文件夹里多选,且不支持多层级多选
         * 欢迎补充完善
         */
        // 需要判断一开始有没有空的
        // 若是一开始选择数组里是空的,直接retrun,不让操作,(或是把当前激活的窗口选中,并放到数组中,暂不实现这种方式)
        if (batchSelectTree.value.length == 0) return;
        let showNodes = node.parent.childNodes;

        let start = batchSelectTree.value[0]; //数值列里第一个
        let startIndex = showNodes.map((el) => el.data.id).indexOf(start.id);
        let endIndex = showNodes.map((el) => el.data.id).indexOf(data.id); //当前的node
        // console.log(start, startIndex, endIndex, "开始索引");
        if (startIndex > endIndex) {
            // 往上选择
            await cancelSelectTree();
            for (let index = startIndex; index >= endIndex; index--) {
                const el = showNodes[index];
                treeRef.value.setChecked(el.data.id, true);
                batchSelectTree.value.push(el.data);
            }
        } else {
            // 往下选择
            await cancelSelectTree();
            for (let index = startIndex; index <= endIndex; index++) {
                const el = showNodes[index];
                treeRef.value.setChecked(el.data.id, true);
                batchSelectTree.value.push(el.data);
            }
        }
    } else {
        // 都有点击,当做都没点击处理
        treeRef.value.setCheckedKeys([data.id]);
        batchSelectTree.value = [data];
    }
};

// 取消原来的选中
const cancelSelectTree = () => {
    batchSelectTree.value.forEach((el) => {
        treeRef.value.setChecked(el.id, false);
    });
    batchSelectTree.value = [];
};

参考:

;