前言

技术栈:vue + Quasar Framework
在开发的时候想要在树结构里面每个节点数据都能实现某种功能(像表格一样有操作的功能),而且不能确定数据有多少层级。基于后续会想要添加节点间互相拖拽的功能,这里使用UI框架提供的树组件不理想,故用vue写一个。
vue 根据有多个子节点的数据动态生成树结构。


一、思路

写一个树结构的封装组件,因为不知道数据的层级,所以在封装的组件里面调用自身,实现一个自身组件的嵌套,我们只需要在嵌套组件的时候做好有子节点才嵌套,无则不嵌套的判断。

二、封装组件的代码

1.组件里的template

class=“row bg_row” 这种样式的写法是Quasar Framework框架里自带的,需要去看文档,如果没有用这个框架的,样式自己写,这里不用理会。

<template>
  <div id="children_tree">
  	<!-- 将数据正常地循环展示 - 组件传入数据数组 parentTreeData -->
    <div v-for="item in parentTreeData" :key="item.category_id">
      <div class="row bg_row">
        <!-- 数据的左边部分 - showHidden点击方法是控制节点是否展开 -->
        <div class="col" @click="showHidden(item)">
          <i
            v-if="
              item.son &&
              item.son instanceof Array && 
              item.son.length > 0 &&
              !findTrue(item.category_id)
            "
            class="material-icons draicon"
            >arrow_right</i
          >
          <i
            v-else-if="
              item.son &&
              item.son instanceof Array && 
              item.son.length > 0 &&
              findTrue(item.category_id)
            "
            class="material-icons draicon"
            >arrow_drop_down</i
          >
          <i
            v-else
            class="material-icons draicon"
            style="padding-left: 38px"
          ></i>
          {{ item.name }}
        </div>
        <!-- 数据的右边放功能按钮的部分 - 接收传入的功能数组 btnOperates -->
        <div :class="`col-${5}`" style="text-align: right">
          <q-btn
            class="on-left"
            v-for="(btn, index) in btnOperates"
            :key="`btn_fun_${index}`"
            :label="btn.label || '按钮'"
            :color="btn.color || 'primary'"
            :outline="btn.outline || false"
            :size="btn.size || 'md'"
            @click="btn.fun(item)"
            unelevated
          />
        </div>
      </div>
      <!-- 调用自己 -->
      <children
        v-if="item.son && findTrue(item.category_id)"
        :key="item.category_id + 10000"
        :parent-tree-data="item.son"
        :tree-data="treeData"
        :btn-operates="btnOperates"
        style="margin-left: 15px"
      ></children>
    </div>
  </div>
</template>

2.组件里的script

<script>
export default {
  name: 'children',
  props: {
    // 传入数据
    parentTreeData: {
      type: Array,
      default: () => {
        return []
      }
    },
    // 功能按钮
    btnOperates: {
      type: Array,
      default: () => {
        return []
      }
    }
  },
  data() {
    return {
      // 用于存储是否展开显示的层级
      showArr: []
    }
  },
  methods: {
    // 展开或者隐藏下级目录
    showHidden(item) {
      if (this.showArr.includes(item.category_id)) {
        // 存在
        this.remove(this.showArr, item.category_id)
      } else {
        // 不存在
        this.showArr.push(item.category_id)
      }
    },
    remove(arr, item) {
      for (let index = 0; index < arr.length; index++) {
        const element = arr[index]
        if (element == item) {
          arr.splice(index, 1)
        }
      }
    },
    // 是否展示
    findTrue(id) {
      return this.showArr.includes(id)
    }
  }
}
</script>

3.style

.bg_row {
  width: 100%;
  height: 50px;
  line-height: 50px;
  background-color: #eeeeee;
  color: #000000;
  margin: 2px 0 2px 0;
}

.draicon {
  font-size: 32px;
  color: #7e7e7e;
  padding-left: 6px;
}

三、使用步骤

1.调用组件

<cate-tree
   :parentTreeData="list"
   :btnOperates="operates"
/>

2.传入数据

import cateTree from './components/cate-tree' // 组件名称自定义哈
export default {
	components: { cateTree },
	data() {
	    return {
	      list: [
	        {
	          category_id: 100,
	          name: '父级一',
	          parent_id: 0,
	          son: [
	            {
	              category_id: 103,
	              name: '子级一',
	              parent_id: 100,
	              son: [
	                {
	                  category_id: 106,
	                  name: '孙级一',
	                  parent_id: 103,
	                  son: [
	                    {
	                      category_id: 107,
	                      name: '曾孙级一',
	                      parent_id: 106
	                    }
	                  ]
	                }
	              ]
	            }
	          ]
	        },
	        {
	          category_id: 101,
	          name: '父级二',
	          parent_id: 0,
	          son: [
	            {
	              category_id: 104,
	              name: '子级一',
	              parent_id: 101
	            }
	          ]
	        },
	        {
	          category_id: 102,
	          name: '父级三',
	          parent_id: 0,
	          son: []
	        }
	      ],
	      operates: [
	        {
	          label: '當前分類商品',
	          color: 'primary',
	          size: 'md',
	          outline: true,
	          fun: (row) => {
	            // 放功能方法
	          }
	        },
	        {
	          label: '修改',
	          color: 'primary',
	          size: 'md',
	          outline: false,
	          fun: (row) => {
	            // 放功能方法
	          }
	        },
	        {
	          label: '刪除',
	          color: 'red',
	          size: 'md',
	          outline: false,
	          fun: (row) => {
	            // 放功能方法
	          }
	        }
	      ]
	    }
    }
}

3.实现的效果

如下图(部分展开)
vue部分展开的树结构
(全部展开)
vue多级全部展开的树结构


总结

传入的数据改成是接口获取,因为是组件调用自身,所以不管数据有多少层级,都能渲染。

Logo

前往低代码交流专区

更多推荐