封装递归tree组件

简介: 封装递归tree组件

封装递归tree组件

效果

image.png

treeCom.vue组件

<template>
  <div class="treeStyle">
    <div 
    class="treeOne"
    v-for="(item,inx) in treeDataNew"
    :key="inx"
    @click.stop.prevent="openShow(item)"
    >
    <div 
    :class="curNameId == item.id ? 'treeTitles activeStyles' : 'treeTitles'" 
    @click.prevent="hClickTreeItem(item)">
      <i v-if="item.children && item.children.length > 0" :class="item.isOpen ? 'el-icon-arrow-down iconR' : 'el-icon-arrow-right iconR'"></i>
      <i v-if="item.children && item.children.length > 0" :class="item.isOpen ? 'el-icon-folder-opened file_icon' : 'el-icon-folder file_icon'"></i>
      <i v-else class="el-icon-folder file_icon"></i>
      <span class="treeName">{
   
   {
   
    item.name }}</span>
    </div>
    <div v-show="item.isOpen && item.children && item.children.length > 0" class="childStyle">
      <treeCom
      :treeData="item.children"
      :current="curNameId"
      @tree-node-click="$emit('tree-node-click', $event)"/> 
    </div>
  </div>
  </div>
</template>
<script>
import treeCom from './treeCom.vue'
export default {
   
   
  props: {
   
   
    treeData: {
   
   
      type: Array,
      default: () => [],
    },
    current: String,
  },
  name: 'treeCom',
  data(){
   
   
    return {
   
   
      treeDataNew: [],
      curNameId: ''
    }
  },
  watch: {
   
   
    //监听当前点击节点的id
        current: {
   
   
            handler(num) {
   
   
                this.curNameId = num
            },
            deep: true,
            immediate: true
        }
    },
  components: {
   
   
    treeCom,
  },
  mounted(){
   
   
    this.treeDataNew = this.treeData
  },
  methods: {
   
   
    openShow(item) {
   
   
      this.$nextTick(() => {
   
   
        item.isOpen = !item.isOpen;
      });
    },
    hClickTreeItem(item){
   
   
      this.$emit('tree-node-click', item)
    },
  },
}
</script>
<style lang="less" scoped>
.treeName {
   
   
    width: 118px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: inline-block;
    position: relative;
    top: 7px;
  }
.treeStyle {
   
   
  .treeOne,
  .childStyle {
   
   
    cursor: pointer;
    // padding-left: 10px;  // 放开,需要注释 ***** 里的代码,会出现选中border距离左边有距离的问题
  }
  .treeTitles {
   
   
    padding-left: 15px;
    font-size: 16px;
    color: #000000;
    box-sizing: border-box;
    font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
  }
  .activeStyles {
   
   
    border: #409EFF 2px solid;
    border-radius: 2px;
    color: #409EFF;
  }
  .file_icon {
   
   
        margin: 8px 8px 8px 0;
    }
  .iconR {
   
   
    margin-right: 6px;
  }

  // ***********************************************
    .childStyle {
   
   
    .treeTitles {
   
   
      position: relative;
    }
    .file_icon {
   
   
      margin-left: 29px;
    }
    .iconR {
   
   
      position: absolute;
      top: 8px;
      left: 25px;
    }
  }
  .treeStyle {
   
   
    .treeStyle {
   
   
      .file_icon {
   
   
        margin-left: 39px;
      }
    }
  }
// ***********************************************
}
</style>

父组件

<template>
  <div class="cont_c">
    <div class="cont_l">
      <div class="tree">
        <tree-com
        :treeData="treeData"
        :current="curNameId" 
        @tree-node-click="nodeClick"
        />
      </div>
    </div>
    <div class="cont_r rightSty">
      <div style="padding: 20px;">{
   
   {
   
   clickData}}</div>
    </div>
  </div>
</template>
<script>
import treeCom from '../model/treeCom.vue'
export default {
   
   
  data(){
   
   
    return {
   
   
      treeData: [
        {
   
   
          "id": "1402903753264885762",
          "isOpen": true,
          "name": "一级父层",
          "status": true,
          "level": "一级菜单",
          "parentId": "0",
          "sortOrder": 7,
          "children": [
            {
   
   
              "id": "1402904547628376065",
              "isOpen": false,
              "name": "123",
              "status": true,
              "level": "二级菜单",
              "parentId": "1402903753264885762",
              "sortOrder": 5,
              "children": [

              ]
            },
            {
   
   
              "id": "1402904663936425985",
              "isOpen": false,
              "name": "456",
              "status": true,
              "level": "二级菜单",
              "parentId": "1402903753264885762",
              "sortOrder": 12,
              "children": [
                {
   
   
                  "id": "1402904949253955585",
                  "isOpen": false,
                  "name": "测试1",
                  "status": true,
                  "level": "三级菜单",
                  "parentId": "1402904663936425985",
                  "sortOrder": 2,
                  "children": [

                  ]
                },
                {
   
   
                  "id": "1402904920229371906",
                  "isOpen": false,
                  "name": "测试2",
                  "status": true,
                  "level": "三级菜单",
                  "parentId": "1402904663936425985",
                  "sortOrder": 10,
                  "children": [

                  ]
                },
                {
   
   
                  "id": "1402904973903880194",
                  "isOpen": false,
                  "name": "测试3",
                  "status": true,
                  "level": "三级菜单",
                  "parentId": "1402904663936425985",
                  "sortOrder": 10,
                  "children": [

                  ]
                }
              ]
            },
            {
   
   
              "id": "1402904645955444738",
              "isOpen": false,
              "name": "888-2",
              "status": true,
              "level": "二级菜单",
              "parentId": "1402903753264885762",
              "sortOrder": 14,
              "children": [

              ]
            },
            {
   
   
              "id": "1402904723365519361",
              "isOpen": false,
              "name": "999-3",
              "status": true,
              "level": "二级菜单",
              "parentId": "1402903753264885762",
              "sortOrder": 30,
              "children": [

              ]
            }
          ]
        }  
      ],
      curNameId: '',
      clickData: null,
    }
  },
  components: {
   
   
    treeCom,
  },
  mounted(){
   
   
    this.curNameId = this.treeData[0].id
  },
  methods: {
   
   
    nodeClick(val) {
   
   
      this.curNameId = val.id
      this.$set(val, 'curNameId', this.curNameId)
      this.clickData = val;
    },
  },
}
</script>
<style lang="less" scoped>
.headerTit {
   
   
  color: #444;
  font-size: 18px;
}
.cont_header {
   
   
  margin-bottom: 18px;
  margin-top: 20px;
  border-bottom: 1px solid #ddd;
  margin-left: 0;
  p {
   
   
    margin-left: 20px;
  }
}
.cont_c {
   
   
  display: flex;
  border-radius: 20px;
  height: 85vh;
}
.cont_l {
   
   
  width: 223px;
  flex-shrink: 0;
  background-color: #fff;
  border-radius: 10px 0 0 10px;
}
.cont_r {
   
   
  flex-grow: 1;
  overflow: hidden;
  background-color: #fafafa;
  border-radius: 10px;
}
.rightSty {
   
   
  border-top-left-radius: 0 !important;
  border-bottom-left-radius: 0 !important;
}
</style>

参考
vue递归组件—开发树形组件Tree--(构建树形菜单)

vue递归组件怎么使用,手写递归组件tree下拉列表。

目录
相关文章
|
6月前
|
存储 算法
树(Tree) - 概念与基础
树(Tree) - 概念与基础
109 2
|
6月前
【sgTree】自定义组件:加载el-tree树节点整棵树数据,实现增删改操作。
【sgTree】自定义组件:加载el-tree树节点整棵树数据,实现增删改操作。
|
6月前
|
JavaScript
node.js递归拼凑成树形结构
node.js递归拼凑成树形结构
35 0
|
6月前
|
JSON 前端开发 Java
|
6月前
KD树的构建(递归
KD树的构建(递归
103 0
|
JavaScript
使用JS递归处理树状结构数据
使用JS递归处理树状结构数据
185 0
使用JS递归处理树状结构数据
|
前端开发 JavaScript
el-tree树组件的懒加载写法步骤
el-tree树组件的懒加载写法步骤
604 0
|
前端开发
el-tree懒加载中使用递归更改树节点状态值
el-tree懒加载中使用递归更改树节点状态值
250 0
|
JavaScript
树形组件(可动态添加属性、无限嵌套)及递归展示tree数据
树形组件(可动态添加属性、无限嵌套)及递归展示tree数据
树形组件(可动态添加属性、无限嵌套)及递归展示tree数据