一:简介

           选择器点击显示带有复选框的下拉选择器,并且支持带有父子关系的多选功能,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无法被通过代码设置选中,则和禁用状态同时使用时就不能支持五层以上的数据结构回显了。

GitHub 加速计划 / eleme / element
54.06 K
14.63 K
下载
A Vue.js 2.0 UI Toolkit for Web
最近提交(Master分支:3 个月前 )
c345bb45 7 个月前
a07f3a59 * Update transition.md * Update table.md * Update transition.md * Update table.md * Update transition.md * Update table.md * Update table.md * Update transition.md * Update popover.md 7 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐