2020-08-04

vue+element穿梭树组件记录

近期公司要求实现穿梭树功能,而element上只有穿梭框和树型控件
看了很多文章,在其中发现了很多大神实现的过程,还有一个很不错的组件

组件实现

el-tree-transfer
文档也很详细

代码实现

将其中大概分离了一下,直接复制就可以使用了
原文地址

<template>
    <div>
        <el-button type="primary" @click="dialogVisible = true">
            穿梭树
        </el-button>
        <el-dialog
            title="编辑"
            :visible.sync="dialogVisible"
            width="45%"
        >
            <div class="addInfoStyle">
                <div>
                    <span>权限:</span>
                    <div style="margin:0px 20px;">
                        <div style=" float: left;    border: 1px solid #ccc;padding: 10px;    width: 230px;">
                            <div>未有权限</div>
                            <el-tree
                                ref="unOwnTree"
                                style="height: 330px;overflow-y: auto;"
                                :data="data"
                                default-expand-all
                                show-checkbox
                                node-key="id"
                                highlight-current
                                :props="defaultProps"
                            />
                        </div>
                        <div style=" float: left;">
                            <button @click="removeRight">
                                <i class="el-icon-d-arrow-right" />
                            </button>
                            <br>
                            <button @click="removeLeft">
                                <i class="el-icon-d-arrow-left" />
                            </button>
                        </div>
                        <div style=" float: right; border: 1px solid #ccc;padding: 10px;    width: 230px;">
                            <div>已有权限</div>
                            <el-tree
                                ref="ownTree"
                                style="height: 330px;overflow-y: auto;"
                                :data="ownPermissions"
                                default-expand-all
                                show-checkbox
                                node-key="id"
                                highlight-current
                                :props="defaultProps"
                            />
                        </div>
                    </div>
                </div>
            </div>
            <div style="clear: both" />
            <span slot="footer" class="dialog-footer">
                <el-button @click="dialogVisible = false">取 消</el-button>
                <el-button type="primary" @click="save">确 定</el-button>
            </span>
        </el-dialog>
    </div>
</template>

<script>
let currentTree;
export default {
    name: 'Infomationtree',
    components: {},
    data () {
        return {
            data: [{
                id: 1,
                label: '一级 1',
                children: [{
                    id: 4,
                    label: '二级 1-1',
                    children: [{
                        id: 9,
                        label: '三级 1-1-1'
                    }, {
                        id: 10,
                        label: '三级 1-1-2'
                    }]
                }]
            }, {
                id: 2,
                label: '一级 2',
                children: [{
                    id: 5,
                    label: '二级 2-1'
                }, {
                    id: 6,
                    label: '二级 2-2'
                }]
            }, {
                id: 3,
                label: '一级 3',
                children: [{
                    id: 7,
                    label: '二级 3-1'
                }, {
                    id: 8,
                    label: '二级 3-2'
                }]
            }],
            defaultProps: {
                children: 'children',
                label: 'label'
            },
            dialogVisible:false,
            ownPermissions:[], // 已拥有的树权限数据
        };
    },
    mounted () {},
    methods: {
        removeRight(){
            let $unOwnTree = this.$refs.unOwnTree;
            let checkedNodes = $unOwnTree.getCheckedKeys();
            console.log("removeRight:",checkedNodes);
            checkedNodes.forEach(item =>{
                let node = $unOwnTree.getNode(item);
                let nodeData = $unOwnTree.getCheckedNodes(item);
                if (node !== null){
                    currentTree = this.$refs.ownTree;
                    this.appendNode(node);
                    $unOwnTree.remove(node,nodeData);
                }
            });

            clearInterval(this.interval); // 当移过来的不为空是,停止定时任务。
        },
        removeLeft(){
            let $ownTree = this.$refs.ownTree;
            let checkedNodes = $ownTree.getCheckedKeys();
            console.log("removeLeft:",checkedNodes);
            checkedNodes.forEach(item =>{
                let node = $ownTree.getNode(item);
                let nodeData = $ownTree.getCheckedNodes(item);
                if (node !== null){
                    currentTree = this.$refs.unOwnTree;
                    this.appendNode(node);
                    // 移除左边的
                    $ownTree.remove(node,nodeData);
                }
            });
        },
        appendNode(node){
            // 1、如果移动的是一级目录
            //   ①先判断 当前目录 在右边一个目录的位置
            // 先判断是否为一级目录
            if (node.level === 1){ // level = 1 说明是一级目录
                // 获取节点的 id
                const oneMenuNodeData = node.data;
                this.oneMenuHandle(oneMenuNodeData);
                /*
                * 2、如果移动的是二级目
                *   ① 当右边没有一级目录时
                *       一、先要获取一级目录数据
                *       二、查看应该插入右边目录位置
                *   ② 当右边有一级目录
                *       一、先要获取二级目录的位置
                */
            }else if(node.level ===2){
                const oneMenu = JSON.parse(JSON.stringify(node.parent.data)); // 深度拷贝 才不会影响到 左侧的树结构
                oneMenu.children = [node.data];
                this.oneMenuHandle(oneMenu);
                /*
                    * 3、如果移动的是权限
                    *   ① 当右边没有一级目录时
                    *       一、当没有二级目录时
                    *           1、创建,二级目录,一个目录,直接迁移
                    *       二、当有二级目录时
                    *           判断权限插入的位置
                    *   ② 当右边有一级目录
                    *       一、有二级目录。
                    *               判断权限插入位置
                    *       二、没有二级目录
                    *               把二级目录一起迁移过去
                    **/
            }else { // 移动的是权限
                const ownTowMenuId = node.parent.data.id;
                let towMenuNode = currentTree.getNode(ownTowMenuId);
                if (towMenuNode === null){ //当没有二级菜单
                    const ownOneMenuId = node.parent.parent.data.id;
                    let oneMenuNode = currentTree.getNode(ownOneMenuId);

                    let removeTowMenuData = JSON.parse(JSON.stringify(node.parent.data));
                    // 将权限放到二级菜单中
                    removeTowMenuData.children = [node.data];
                    if (oneMenuNode === null){ // 当没有一级菜单
                        let removeOneMenuData = JSON.parse(JSON.stringify(node.parent.parent.data));
                        removeOneMenuData.children = [removeTowMenuData];
                        this.oneMenuHandle(removeOneMenuData);
                    } else{ // 当有一级菜单
                        this.oneMenuHandle(removeTowMenuData);
                    }
                } else { //当有二级菜单
                    this.towMenuHandle(node.data,towMenuNode);
                }
            }
        },
        // 当有二级目的时候
        towMenuHandle(permission, towMenuNode){
            // 获取二级目录下面所有权限
            let ownPermissions = towMenuNode.data.children;
            let ownPermissionsArr = [];
            ownPermissions.forEach(permission =>{
                ownPermissionsArr.push(permission.id);
            });
            this.toInsert(ownPermissionsArr,permission);
        },
        oneMenuHandle(oneMenuNodeData){
            let ownOneMenu = currentTree.getNode(oneMenuNodeData.id);
            if (ownOneMenu === null) { // 说明右边未拥有
                // 获取右边所有的一级目。
                const ownTreeDataArr = currentTree.data;
                let ownOneMenus = [];
                ownTreeDataArr.forEach(oneMenu =>{
                    ownOneMenus.push(oneMenu.id);
                });
                // 获取当前一级目录附近的一级目录的 id 和 插入当前id 之前还是之后。
                if (ownOneMenus.length >0){
                    this.toInsert(ownOneMenus,oneMenuNodeData);
                }else {
                    currentTree.append(oneMenuNodeData,0);
                }
            }else{ // 右边拥有一级目录时
                // 需要右移的二级目录 遍历进行插入
                let rightMoveTowMenu = oneMenuNodeData.children;
                rightMoveTowMenu.forEach(towMenu =>{
                    let ownTowMenu = currentTree.getNode(towMenu.id); // 获取右边拥有的二级目录
                    if(ownTowMenu === null){ // 如果不存在
                        let ownTowTreeDataArr = ownOneMenu.data.children;
                        let ownTowMenus = [];
                        ownTowTreeDataArr.forEach(oneMenu =>{
                            ownTowMenus.push(oneMenu.id);
                        });
                        this.toInsert(ownTowMenus,towMenu);
                    }else{ // 如果存在
                        let ownPermissions = [];
                        // 获取原来的 二级目录下的所有的权限
                        ownTowMenu.data.children.forEach(ownPermission =>{
                            ownPermissions.push(ownPermission.id);
                        });
                        // 得到 要移动的二级目录下的所有权限
                        towMenu.children.forEach(unOwnPermission =>{
                            this.toInsert(ownPermissions,unOwnPermission);
                        });
                    }
                });
            }
        },
        // 获取当前一级目录附近的一级目录的 id 和 插入当前id 之前还是之后。
        getNearbyOneMenu(ownOneMenus,oneMenuId){
            let nearbyId = -1;
            let isBefore = false;
            ownOneMenus.some(id =>{
                if (oneMenuId<id){
                    nearbyId = id;
                    isBefore = true;
                    return true;
                }
            });
            // 如果 nearbyId !== -1 则将 ownOneMenus 数组中最大的赋值给 nearbyId
            nearbyId = nearbyId !== -1?nearbyId:ownOneMenus[ownOneMenus.length-1];
            return {nearbyId:nearbyId,isBefore:isBefore};
        },
        toInsert(arr,toMoveNode){
            const nearbyOnePermission = this.getNearbyOneMenu(arr.sort(),toMoveNode.id);
            if (nearbyOnePermission.isBefore) {
                currentTree.insertBefore(toMoveNode,nearbyOnePermission.nearbyId);
            }else{
                currentTree.insertAfter(toMoveNode,nearbyOnePermission.nearbyId);
            }
        },
    }
};
</script>

<style lang='scss' scoped>
</style>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值