Element-plus el-tree , el-select 联动实现 懒加载节点的树形选择器

 一:简介

           选择器点击显示带有复选框的下拉选择器,并且支持带有父子关系的多选功能,Element-plus虽然存在el-tree-select 这一树形选择器,但是当下拉框节点是懒加载状态时且存在字父级关系(当选中父级时懒加载之后的子集在展开之后同样会被自动选中)时,如果要选择某一选框,则只能在树形结构懒加载完全展开之后的叶子节点才能被选中,否则是无法被选中的,此时就违背懒加载的初衷。

        而使用el-tree, el-select 则可以实现在存在严格的父子关系的状态下,在整个树形结构没有完全加载之前,可以选中当前加载的任意节点

二:Dom元素结构

              <el-select
                  v-model="dirSelect"
                  placeholder="请选择"
                  :collapse-tags="true"
                  @remove-tag="removeDirTag"
                  :collapse-tags-tooltip="true" multiple>
                <el-option 
                  style="
                    height: 100%;
                    max-height: 200px;
                    overflow-y: auto;
                    padding: 0;
                    background-color: #ffffff;">
                  <el-tree  
                    v-model="treeOption"
                    ref="treeSelectRef"
                    node-key="value"
                    :load="loadNode"
                    :props="props"
                    :render-after-expand="true"
                    :show-checkbox="true"
                    lazy
                    @check-change="handleCheckChange">

                  </el-tree>
                </el-option>
              </el-select>

三:数据回显业务

因为是懒加载树形节点,则需要根据返回值进行分批次回显数据,而返回的数据也应该是分组数据,这样才能在节点加载之后准确回显,主要使用:load 、setChecked、

//变量
const state = reactive<any>({
    checkDirEchoInfo: {}, //保存授权目录分层回显的所有信息
    dirSelect:[]          //用户select回显标签
  })
//分层回显核心逻辑
const loadNode = (node:any, resolve:any) => {
  if (node.isLeaf) return resolve([])
  if(node.level === 0){
    getDept().then((res)=>{
      console.log('dept00000',res.data)
      if(res && res.status as any === '200'){
        if(!res.data){
          resolve([])
        }else{
          resolve(
          res.data.map((item:any)=>{
            return {
              label:item.deptName,
              value:item.code,
              type:'dept',
              parentCode:'-',
            }
          })
        )
        }
      }
    })
  }else if(node.level === 1){
    let params = {
      deptCode:node.data.value,
      pageNum:1,
      pageSize:20
    }
    projectList(params).then((res)=>{
      console.log('dept1',res.data)
      if(res && res.status as any === '200'){
        console.log('projectList',res.data.records)
        if(!res.data){
          resolve([])
        }else{
          let temp = res.data.records.map((item: any) => {
            return {
              value: item.projectInfo.code,
              label: item.projectInfo.projectName,
              parentCode: item.projectInfo.departmentCode,
              type: "project",
            };
          });
          resolve(temp);
          console.log("当前加载的第二层节点", temp);
          //将第二层节点用排除法进行回显
          if (temp.length > 0) {
            let checked = false;
            let allChecked = false;
            temp.forEach((el: any) => {
              console.log(el.parentCode);
                if(state.checkDirEchoInfo.project.length>0){
                  state.checkDirEchoInfo.project.forEach((item: any) => {
                  console.log("code", el.value === item.contentsCode);
                  if (el.value === item.contentsCode) {
                    //当前子节点被选中
                    checked = true;
                    //是否存在子节点被选中
                    allChecked = true;
                  }
                });
                }
                //设置当前节点是否被勾选,若勾选则并递归选择子节点
              treeSelectRef.value.setChecked(el.value, checked, true);
              //更新标识
              checked = false;
            });
            //如果当第二层没有一个被选中,且其父元素是被选中的,则设置当前层全选
            if (!allChecked) {
              state.checkDirEchoInfo.dept.forEach((item: any) => {
                if (temp[0].parentCode === item.contentsCode) {
                  //此时该层元素均为选中状态,并且默认递归选中子节点中的数据
                  treeSelectRef.value.setChecked(temp[0].parentCode,true,true);
                }
              });
              allChecked = false;
            }
          }
        }
      }
    })

  }else if(node.level === 2){
    getProjectDirectory(false,node.data.value).then((res)=>{
      if(res && res.status as any === '200'){
        if (!res.data) {
          resolve([]);
        } else {
          let temp = res.data.map((item: any) => {
            return {
              value: item.code,
              label: item.directoryName,
              parentCode: item.projectCode,
              children: item.sonDirectoryList,
              isLeaf: item.sonDirectoryList ? false : true,
              type: !item.isDirectory ? "file" : "Directory",
            };
          });
          resolve(temp);
          if (temp.length > 0) {
            let checked = false;
            let allChecked = false;
            //获取当前层加载前的所有被选中的节点
            let checkedNodes = treeSelectRef.value.getCheckedNodes();
            temp.forEach((el: any) => {
              state.checkDirEchoInfo.dirFile.forEach((item: any) => {
                if (el.value === item.contentsCode) {
                  //当前子节点是否被选中
                  checked = true;
                  //当前层是否存在节点被选中
                  allChecked = true;
                }
              });
             //设置当前元素的选中状态,若选中则递归勾选其子节点
              treeSelectRef.value.setChecked(el.value, checked, false);
              checked = false;
            });
            //如果当前一层没有一个被选中,且其父元素是被选中的,则设置当前层全选
            if (!allChecked) {
              checkedNodes.forEach((item: any) => {
                  if (temp[0].parentCode === item.value) {
                      //若其父元素被选中,则默认选勾选当前层所有元素,并递归勾选其子元素
                      treeSelectRef.value.setChecked(temp[0].parentCode,!allChecked,true);
                    }
                });
              allChecked = false;
            }
          }
        }
      }
    })
  }else if(node.level >2){
    let temp = getChild(node.data.children);
    resolve(temp)
    if (temp!==undefined && temp.length > 0) {
      let checked = false;
      let allChecked = false;
      //获取该层加载前所有被选中的元素
      let checkedNodes = treeSelectRef.value.getCheckedNodes();
      temp.forEach((el: any) => {
        state.checkDirEchoInfo.dirFile.forEach((item: any) => {
          if (el.value === item.contentsCode) {
            //当前加载的元素是否被选中
            checked = true;
            //当前层是否存在元素被选中
            allChecked = true;
          }
        });
        treeSelectRef.value.setChecked(el.value, checked, true);
        checked = false;
      });
      //如果当前一层没有一个被选中,且其父元素是被选中的,则设置当前层全选
      if (!allChecked) {
        checkedNodes.forEach((item1: any) => {
          treeSelectRef.value.setChecked(
              temp[0].parentCode,
              !allChecked,
              true
            );
        });
        allChecked = false;
      }
    }
  }
}

四:注意事项,

1,设置node-key为节点设置Key值

2,数据回显不推荐设置禁用状态回显,因为禁用状态下setChedked方法为某一元素设置选中状态时不能自动勾选其子元素,此时如果逻辑补充完整也是能实现功能的,但是经过测试el-tree树形结构只能递归绑定五层数据,第六层数据就会脱离第五层的childrenList属性,通过api无法被通过代码设置选中,则和禁用状态同时使用时就不能支持五层以上的数据结构回显了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
element-plus 是一个基于 Vue.js 的 UI 组件库,el-tree-select 是其中的一个组件,用于实现树形结构的下拉选择。 el-tree-select 组件是在 el-select 组件的基础上进行扩展,使其支持树形结构的数据。使用 el-tree-select,我们可以在下拉列表中展示树状数据,并支持选择树节点的功能。 el-tree-select使用方式大致分为以下几步: 1. 引入 element-plus 库,确保已安装并正确引入相关 CSS 和 JS 文件。 2. 在组件中使用 el-tree-select 标签,通过 v-model 绑定选中的节点,将选中的节点值赋给 data 中的一个变量。 3. 设置 el-tree-select 的配置项,包括数据源、显示字段、样式等。 4. 响应选择事件,在 el-tree-select 标签上绑定 change 事件,根据选中的节点进行相应操作。 配置项中常用的属性有: - data:树形数据源,可以是一个数组或者通过异步加载数据。 - label-prop:用于显示节点文本的属性名。 - value-prop:用于取值的属性名。 - default-expand-all:是否默认展开全部节点。 - filterable:是否支持输入框搜索。 el-tree-select 还提供了其他的配置项和方法,可以根据具体需求进行调整和使用。 总之,element-plus 的 el-tree-select 组件提供了一种简单易用的方式来展示和选择树形数据,在Vue.js项目中非常实用。通过合理配置,我们可以灵活定制树形下拉选择框的功能和样式,使其符合项目的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值