效果图如下:

elementui table Transfer 穿梭框 elementui树形穿梭框_前端

一、需求要求:

1、勾选左侧的功能资源,点击【添加】,可将内容添加到右侧,并且左侧勾选的数据删除;勾选右侧的已选资源,效果同左侧一样;

2、勾选全选,则资源全部添加到右侧,左侧的则显示为空

二、代码如下:

<div>
     <el-row>
       <el-col :span="12">
          <div class="transfer-box">
            <div class="transfer-box-header">
               <el-checkbox @change="getLeftValue" v-model="leftCheck" ><b>可分配的功能资源</b></el-checkbox>
               <div style="float:right; margin-right:10px"><el-button  type="success"  size="small" @click="add">添加<i class="el-icon-arrow-right el-icon--right"></i></el-button></div> 
            </div>
            <div class="transfer-box-content">
               <el-tree
                :data="data"
                show-checkbox
                node-key="resId"
                ref="tree"
                :expand-on-click-node="false"
                :props="defaultProps">
            </el-tree>
            </div>
          </div>
       </el-col>
       <el-col :span="12">
          <div class="transfer-box">
            <div class="transfer-box-header">
               <el-checkbox @change="getRightValue" v-model="rightCheck"><b>已选择的功能资源</b></el-checkbox>
               <div style="float:right; margin-right:10px"><el-button  type="success" icon="el-icon-arrow-left" size="small" @click="del">移除</el-button></div> 
            </div>
            <div class="transfer-box-content">
               <el-tree
                :data="targetData"
                show-checkbox
                node-key="resId"
                :expand-on-click-node="false"
                default-expand-all
                :props="defaultProps"
                ref="treeRight"
            >
            </el-tree>
            </div>
          </div>
       </el-col>
     </el-row>
    </div>

1、先给el-tree绑定显示定义

data() {
    return {
       perId:'',
       btnLoading:false,
       selectedResRows:[],
       leftCheck:'',
       rightCheck:'',
       data:[],
       defaultProps: {
          children: 'children',//子集
          label: 'resName'//显示的文本
        },
      targetData: [],
      getNodeId:[],//初始化时获取所有勾选的id
    };
  },

2、实现左右移除的功能

<script>
function recursion(obj, cb) {
    if (Array.isArray(obj) && obj.length > 0) {
        for (const item of obj) {
            if (item.children) recursion(item.children, cb);
            typeof cb == "function" && cb(obj, item);
        }
    }
}
export default {
  methods: {
    getLeftValue(val){
      console.log(val)
      if(val){
         this.$refs.tree.setCheckedNodes(this.data)
      }
      else{
        this.$refs.tree.setCheckedKeys([])
      }
    },
    getRightValue(val){
      if(val){
         this.$refs.treeRight.setCheckedNodes(this.targetData)
      }
      else{
        this.$refs.treeRight.setCheckedKeys([])
      }
    },
    getTop(){
      let param={
        perId:this.perId
      }
      this.$api.per.getPerDetail(param).then(res => {
          if (res.data.code == "0") {
            this.topInfo = res.data.data;
            this.getAllResTreeList(this.topInfo.mdcKey)
          }
        })
        .catch(error => {
        });
    },
    //获取所有菜单信息
      getAllResTreeList(mdcKey){
        this.$api.resource.selectMenuTreeByMdcKey({mdcKey:mdcKey}).then(res => {
          if(res.data.code == '0'){
            this.data = res.data.data
            this.getPerBindResList()
          }else{
            this.$message({
              type: 'error',
              message: res.data.msg
            });
          }
        })
      },
      add() {
         let selectedKeysLeft = this.$refs.tree.getCheckedKeys();//获取勾选的,不包含父级id
         let selectedNodesLeft = this.$refs.tree.getCheckedNodes(false, true);//获取所有勾选的node
         if(selectedKeysLeft.length>0){
           //复制选择的元素
          this.handleData(selectedKeysLeft,selectedNodesLeft,this.targetData,this.data);
          //重置选择
          this.$refs.tree.setCheckedKeys([]);
          this.leftCheck=false;
          this.rightCheck=false;
        }
        else{
          this.$message.info('请先勾选数据')
        }  
      },
      del() {
         let selectedKeysRight = this.$refs.treeRight.getCheckedKeys();//获取勾选的,不包含父级id
         let selectedNodesRight = this.$refs.treeRight.getCheckedNodes(false, true);//获取所有勾选的node
         if(selectedKeysRight.length>0){
          this.handleData(selectedKeysRight,selectedNodesRight,this.data,this.targetData);
          //重置选择
          this.$refs.treeRight.setCheckedKeys([]);
          this.rightCheck=false;
          this.leftCheck=false;
        }
        else{
          this.$message.info('请先勾选数据')
        }
         
      },
      /**
       *selectedKeys参数为勾选的id,不包含半勾选
       selectedNodes参数为获取所有勾选的node
       targetData参数为操作后获得的结果数据
       data参数为需要操作勾选的源数据 **/
      handleData(selectedKeys,selectedNodes,targetData,data){
        selectedNodes.forEach((nodes) => {
              let parentNode;
              recursion(targetData, function(obj, item) {
                  //寻找要插入的元素的父节点是否存在
                  if (nodes.resParentid == item.resId) parentNode = item;
              });
              //初始化要插入的节点数据
              let nodeObj = {
                  resId: nodes.resId,
                  resName: nodes.resName,
                  resParentid:nodes.resParentid,                   
              };
              nodes.resParentid && (nodeObj.nodeObj = nodes.resParentid);
              nodes.children && (nodeObj.children = []);
              //如果找到父节点,那么代表是子节点,没有找到那么就是一级节点。
              if (parentNode) {
                  //判断父节点是否已经存在这个节点。如果不存在就插入
                  if (
                     !parentNode.children.find((item) => item.resId == nodes.resId)
                  )
                    parentNode.children.push(nodeObj);                     
              } else {
                  //一级节点需要在顶层数组里插入
                  if (!targetData.find((item) => item.resId == nodes.resId))
                      targetData.push(nodeObj);
              }
          });
          //删除选中的元素
          recursion(data, function(obj, item) {
              selectedKeys.forEach((delItem) => {
                  //找到选中的元素删除
                  let index = obj.findIndex((findItem) => {
                      return delItem == findItem.resId;
                  });
                  index > -1 && obj.splice(index, 1);
                  
              });
          });
      },
  },
  created() {
    this.getTop();
  }
};
</script>

3、保存后点击编辑,左侧显示未分配的资源,右侧显示已分配的资源

后台给到的数据是:所有的资源(多维数组)和已分配的资源(一维数组,包含(半勾选)父级数据)

//获取所有菜单信息
      getAllResTreeList(mdcKey){
        this.$api.resource.selectMenuTreeByMdcKey({mdcKey:mdcKey}).then(res => {
          if(res.data.code == '0'){
            this.data = res.data.data
            this.getPerBindResList()
          }else{
            this.$message({
              type: 'error',
              message: res.data.msg
            });
          }
        })
      }, 

//获取当前权限绑定资源信息,一维数组
      getPerBindResList(){
        let that = this
        this.$api.per.selectResListByPerId({perId:this.perId}).then(res => {
          if(res.data.code == '0'){
            that.selectedResRows = res.data.data
              that.selectedResRows.forEach((n) => {
                  //获取tree中的节点
                  var node = that.$refs.tree.getNode(n);
                  if (node.isLeaf) {
                    //获取勾选状态的数据
                    //that.getNodeId.push(node.data.resId)
                    //设置某个节点的勾选状态
                   that.$refs.tree.setChecked(node, true);
                  }
                })
            }
          let selectedKeys = this.$refs.tree.getCheckedKeys();//获取勾选的,不包含父级id
          let selectedNodes = this.$refs.tree.getCheckedNodes(false, true);//获取所有勾选的node
          this.handleData(selectedKeys,selectedNodes,that.targetData,that.data);
          //重新渲染el-tree
          this.data = [...this.data]
        })
      },