vue 树形选择器数据处理 + 搜索查询时每一层级都可选

发布时间 2023-12-05 23:19:41作者: 朱呀朱~

vue 树形选择器

主要用后端处理显示数据

  • 根据 el-Element 官网可知,想要使用树形选择器 <el-tree-select> 就要提供以下形式的数据:

    data = [
      {
        value: '1',
        label: 'Level one 1',
        children: [
          {
            value: '1-1',
            label: 'Level two 1-1',
            children: [
              {
                value: '1-1-1',
                label: 'Level three 1-1-1',
              },
            ],
          },
        ],
      },
      ......
    ]
    
  • 这里本人采用的方法是后端对数据做好处理,即直接向前端提供上述的 data 的结构样式:

    1. 首先建立好所需的树的实体类,主要用到了三个属性:树的编号 treeCode、树的父编号 treeParentCode、树的名称 treeName、树的子树 List<GoodsTree> childrenList

    2. 编写操作为树所需数据的结构:

      // 查所有的tree数据,并整合成前端el-tree-select所需形式:
      
      // 取所有的
      List<GoodsTree> allTree = goodsTreeService.selectTree(null);
      // 存顶层的数据
      List<GoodsTree> resultTree = new ArrayList<>();
      // 存所有的数据
      Map<Object ,GoodsTree> treeMap = new HashMap();
      // 存顶层的键
      List<String> PCodeList = new ArrayList<>();
      
      for (int i = 0; i < allTree.size() && !allTree.isEmpty(); i++){
          // 把所有的数据都放到map中,(code, GoodsTree)的样式
          treeMap.put(allTree.get(i).getTreeCode(), allTree.get(i));
      }
      
      // 循环给父赋childrenList值
      for (int i = 0; i < allTree.size() && !allTree.isEmpty(); i++) {
          GoodsTree goodsTrees = treeMap.get(allTree.get(i).getTreeParentCode()); 
          if (goodsTrees != null) { // 找到父(注意,此处的i为子,allTree.get(i).getTreeParentCode()是为了找到父code)
              PCodeList.add(goodsTrees.getTreeCode()); // 存下父的code
              if (goodsTrees.getChildrenList() == null){ // 若还没有子,就先初始化
                  goodsTrees.setChildrenList(new ArrayList<>());
              } 
              goodsTrees.getChildrenList().add(allTree.get(i)); // 把i子放进父childrenList中
              treeMap.put(allTree.get(i).getTreeParentCode(), goodsTrees); // 跟新父
          }
      }
      
      // 过滤重复的code
      List<String> newList = PCodeList.stream().distinct().collect(Collectors.toList());
      
      // 只获取父的那部分(子已经都包含在了父的childrenList中)
      for (int i = 0; i < newList.size() && !newList.isEmpty(); i++){
          if(treeMap.get(newList.get(i)).getTreeParentCode() == null){
              resultTree.add(treeMap.get(newList.get(i)));
          }
      }
      
      • 实测方法可行,但是要循环三遍,如有更好的方法或优化还望赐教
    3. 前端获取:

      const goodsTreeList = ref([])
      const getTree = () => {
          goodsTreeApi.getAllTree((res) =>{
              // 注意,直接获取不可行,还要化code为value,化name为label,化childrenList为children,要严格遵守格式
              goodsTreeList.value = res.data;
          })
      }
      
      // 以下才是正确的处理方法:
      /**
       * 树的获取
       */
      const goodsTreeList = ref([]) // 商品树
      const getTree = () => {
          goodsTreeApi.getAllTree((res) =>{
              goodsTreeList.value = changeData(res.data);
          })
      }
      const changeData = (data) => {
          return data.map((item) => {
              const newItem = {
                  label: item.treeName,
                  value: item.treeCode,
              };
              if (item.childrenList) { // 如果有子,那就再处理子
                  newItem.children = changeData(item.childrenList); // 递归过程
              }
              return newItem;
          });
      };
      
    4. 前后端都处理后,树形选择器的数据属性就可以直接写了::data="goodsTreeList"

实现树形每一级都可选

  • 功能场景:一般样式就是点击一层级或二层级后只会展开其子数据,即若是根据所选查询,就只能根据最下面的叶层级的来查询

    • 即只能选黄岛、历城,不能选中青岛、济南
  • 但是这里想要做到每一级都可获取,即:选黄岛就只表格显示黄岛的,选青岛就表格显示市南区、市北区、黄岛区、崂山区、李沧区、城阳区、即墨区所有的信息(甚至到市北的纺织谷,只要有子,就都能查到)

  • 我这里用的是比较基础的,最笨的方法(秉着能用就行,能跑就管的思想~),有更好的方法还请赐教

  • 这里先提供思路:

    1. 根据父找子信息

    2. 递归再找每个子下的子信息

    3. 方法就不再细讲,代码如下:

      /**
       * 根据父取所有父子code集合List
       * @param goodsTree
       * @return
       */
      public List<String> selectByTree(GoodsTree goodsTree) {
          String treeCode = goodsTree.getTreeCode();
      
          if (!(treeCode.isEmpty())){
              // 存treeCode下所有code
              List<String> childrenCode = new ArrayList<>();
              childrenCode.add(treeCode);
      
              // 是某个的父树
              if (judge(goodsTree)){
                  // 遍历方法
                  allChildTree(goodsTree, childrenCode);
                  // 获取到存所有的code的list
              }
              return childrenCode;
          }
          return null;
      }
      
      /**
       * 判断是否有子
       * @param goodsTree
       * @return
       */
      public boolean judge(GoodsTree goodsTree) {
          // 查有没有以此为父的子树
          List<GoodsTree> goodsTrees = selectTree(goodsTree);
          if (goodsTrees.size() == 0){
              return false;
          } else {
              return true;
          }
      }
      
      /**
       * 遍历取所有子树code
       * @param fuTree 父code
       * @param childrenCode 父子code集合
       * @return
       */
      public List<String> allChildTree(GoodsTree fuTree, List<String> childrenCode) {
          // 取所有直接的子树
          List<GoodsTree> goodsChildTree = selectTree(fuTree);
          if (goodsChildTree != null){
              for (int i = 0; i < goodsChildTree.size(); i++) {
                  GoodsTree goodsTree1 = goodsChildTree.get(i);
                  childrenCode.add(goodsTree1.getTreeCode());
                  allChildTree(goodsTree1, childrenCode);
              }
          }
          return childrenCode;
      }
      
    4. 返回的 childrenCode 里就是所有的需要的 code 值

  • 树形选择器的编写还是参考官网 https://element-plus.org/zh-CN/component/tree-select.html,描述的很清楚