el-tree实现组织设备树,异步加载,优化搜索,自定义层级隐藏

569 阅读1分钟

产品需求:

  1. 用户组织数据可一次获取全部,组织下的设备则在展开时异步获取
  2. 用户可设置自定义的显示层级,只展示对应层级的节点
  3. 优化树节点过滤方法,匹配的组织将展示下面的子组织,可继续向下展开操作
  4. 节点刷新

image.png

例:浙江省展开时会获取下面的设备,并与下属组织节点合并

根据节点类型调用不同的接口加载数据

/**
 * 根据节点类型调用不同的接口加载数据
 * @param node
 * @param resolve
 */
getTreeData(node, resolve){
  if(node.level === 0 && !node.label){
    // 获取全部组织数据
    getUserOrg().then(res => {
      this.treeAreaData = res.data
      this.treeData = this.onHideTreeLevel(this.treeAreaData)
    }).finally(() => {
      if(this.showCheckbox && this.defaultCheckedAll){
        this.checkedAll()
      }
      this.$refs.tree.filter(this.filterText)
    })
  } else if(node.data.type === 'device'){
    //获取设备下的通道
    this.getDevicesChannels(node, resolve)
  } else {
    // 获取组织下的设备
    this.getNodeDevices(node, resolve)
  }
}

显示用户选择层级


/**
 * 根据用户设置隐藏层级
 */
onHideTreeLevel(treeData, level = 0){
  if(level < this.hideLevel){
    let newTreeArr = []
    treeData.forEach(item => {
      if(item.children){
        newTreeArr = newTreeArr.concat(this.onHideTreeLevel(item.children, level + 1))
      }
    })
    return newTreeArr
  } else {
    return treeData
  }
},

优化树节点过滤方法,匹配的组织将展示下面的子组织 踩坑1:懒加载的树,即使treeData是全的也不会渲染出node,需要主动通过数据进行过滤

/**
 * 树过滤方法
 * @param value
 * @param data
 * @param node
 * @returns {boolean}
 */
filterNode(value, data, node) {
  if (!value) return true;
  if(this.filterType === '1'){
    // 通道
    if(data.type === 'channel'){
      return data.organizeName.indexOf(value) !== -1;
    } else {
      return true
    }
  } else{
    // 组织
    if(data.type === 'channel' || data.type === 'device'){
      return this.getParentMatching(value, data, node)
    } else {
      let parentLike = this.getParentMatching(value, data, node)
      let childLike = false
      if(data.children.length > 0 && node.childNodes.length === 0){
        //懒加载已有数据匹配优化
        childLike = this.getChildMatching(value, data)
      }
      return data.organizeName.indexOf(value) !== -1 || parentLike || childLike;
    }
  }
}
/**
 * 父节点是否匹配
 * @param value
 * @param data
 * @param node
 * @returns {boolean}
 */
getParentMatching(value, data, node){
  let parentLike = false
  let parent = node.level > 1 ? node.parent : null
  while(parent && !parentLike){
    if(parent.data.organizeName.indexOf(value) !== -1){
      parentLike = true
      break
    }
    parent = parent.data.parentId ? parent.parent : null
  }
  return parentLike
}
/**
 * 子数据匹配
 * @param value
 * @param data
 * @returns {boolean}
 */
getChildMatching(value, data){
  let childData = data.children
  let matching = false
  childData.forEach(item => {
    if(item.type !== 'channel' || item.type !== 'device'){
      if(item.organizeName.indexOf(value) !== -1){
        matching = true
      }
    }
    if(item.children && item.children.length > 0){
      let matchingChild = this.getChildMatching(value, item)
      if(matchingChild){
        matching = true
      }
    }
  })
  return matching
}

参数传递优化,树节点子节点全选,只传父节点(例:地市节点全部选中则只传浙江省id)

/**
 * 获取树已选择的id
 * 父节点选中则不用传子节点
 * 按此规则过滤数据
 */
getSelectedIds(){
  let store = this.$refs.tree.store
  const checkedNodes = [];
  const traverse = function(node) {
    const childNodes = node.root ? node.root.childNodes : node.childNodes;
    childNodes.forEach(child => {
      if (child.checked) {
        checkedNodes.push(child.data);
      }
      if (child.indeterminate) {
        traverse(child);
      }
    });
  };
  traverse(store)
  return checkedNodes;
}

节点刷新

/**
 * 刷新节点
 * @param data
 * @param node
 */
handleNodeFresh(data, node){
  node.loading = true
  let oldExpanded = node.expanded // 记录当时展开状态
  node.expanded = false
  node.data.children = node.data.children.filter(item => {
    return item.type !== 'device' && item.type !== 'channel'
  })
  // 记录当前选中数据
  let checkedNodeKeys = this.$refs.tree.getCheckedKeys()
  new Promise(resolve => {
    this.getTreeData(node, resolve)
  }).then(res => {
    this.$refs.tree.updateKeyChildren(data.id, res)
    node.expanded = oldExpanded // 还原展开状态
  }).finally(() => {
    if(this.showCheckbox){
      //重新选中数据
      this.$refs.tree.setCheckedKeys(checkedNodeKeys)
    }
    node.loading = false
  })
},

小技巧: 1.可以通过$refs.tree.store获取整棵树的nodes根节点