vue树形组件的实现

1. 效果

一共分为三级,一级标题默认显示,一级和二级标题点击可展开:
在这里插入图片描述

需要提供以下格式的数据titles:

 data() {
    return {
      titles: [
        {
          first: '一级标题1',
          seconds: [
            {
              second: '二级标题1',
              thirds: ['三级标题1', '三级标题2', '三级标题3']
            },
            {
              second: '二级标题2',
              thirds: ['三级标题4', '三级标题5', '三级标题6']
            }
          ]
        },
        {
          first: '一级标题2',
          seconds: [
            {
              second: '二级标题3',
              thirds: ['三级标题7', '三级标题8', '三级标题9']
            },
            {
              second: '二级标题4',
              thirds: ['三级标题10', '三级标题11', '三级标题12']
            }
          ]
        },
        { first: '一级标题3', seconds: [] }
      ]
    }
  },

2. 上代码

Tree.vue里的代码:

<template>
  <div id="tree">
    <div class="wrapper">
      <div v-for="(item) in newTitles" :key="item.ID">
        <div @click="titleChange(item.ID)" class="titleFirst">
          <tree-svg :Isshow="item.IsOpen" class="treesvg"></tree-svg>
          <span>{{item.first}}</span>
        </div>
        <div v-for="item2 in item.seconds" :key="item2.ID">
          <div v-if="item.IsOpen" @click="title2Change(item2.ID)" class="titleSecond">
            <tree-svg :Isshow="item2.IsOpen" class="treesvg2"></tree-svg>
            <span>{{item2.second}}</span>
          </div>
          <div class="titleThird" v-for="(item3,index) in item2.thirds" :key="index">
            <div v-if="item2.IsOpen&&item.IsOpen">{{item3}}</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      newTitles: [] // 重构后的数据结构
    }
  },
  props: ['titles'], // 传入原始数据结构
  methods: {
    titleChange(ID) { // 一级标题点击事件
      this.newTitles.forEach((item, index) => {
        if (item.ID === ID) {
          this.newTitles[index].IsOpen = !this.newTitles[index].IsOpen
        }
      })
    },
    title2Change(ID) { // 二级标题点击事件
      this.newTitles.forEach((item, index) => {
        item.seconds.forEach((item2, index2) => {
          if (item2.ID === ID) {
            this.newTitles[index].seconds[index2].IsOpen = !this.newTitles[
              index
            ].seconds[index2].IsOpen
          }
        })
      })
    }
  },
  components: {
    TreeSvg: () => import('./tree/TreeSvg.vue')
  },
  mounted() { // 对数组进行重构
    this.newTitles = this.titles.map((item, index) => {
      const newSeconds = item.seconds.map((item2, index2) => {
        return {
          ...item2,
          IsOpen: false,
          ID: index2
        }
      })
      return {
        first: item.first,
        seconds: newSeconds,
        IsOpen: false,
        ID: index
      }
    })
  }
}
</script>

<style lang="less" scoped>
#tree {
  .titleFirst {
    font-size: 20px;
  }
  .treesvg {
    display: inline-block;
  }
  .titleSecond {
    font-size: 18px;
    margin-left: 10px;
    .treesvg2 {
      display: inline-block;
      margin-right: 2px;
    }
  }
  .titleThird {
    margin-left: 35px;
  }
}
</style>

显示箭头方向的组件TreeSvg.vue:

<template>
  <div id="treesvg">
    <svg v-if="!Isshow"> // 方向向右的svg
      <polyline points="2,2.5 9.5,10 2,17.5" style="fill:none;stroke:black;stroke-width:2" />
    </svg>
    <svg v-if="Isshow"> // 方向向下的svg
      <polyline points="2,7 10,14 18,7" style="fill:none;stroke:black;stroke-width:2" />
    </svg>
  </div>
</template>

<script>
export default {
  props: ['Isshow']
}
</script>

<style lang="less" scoped>
#treesvg {
  svg {
    width: 20px;
    height: 20px;
  }
}
</style>

引用组件如下,其中的titles的数据结构已在上方演示:

<Tree :titles="titles"></Tree>

3. 分析

  • 利用的vue的用数据操作dom的思想,定义了数组newTitles,dom的渲染依据的就是newTitle这个数组。这个数组里面每一级标题的内容、是否展开、下级标题的信息都储存在标题对象里。
  • 实现的核心是对原始数组titles的重构,用到了数组的map方法,为原始数组的每个标题对象添加了是否展开这样一个属性,而当点击相应的标题时,则修改对应标题对象的这个属性即可。
  • 这个组件的实现用到了许多vue基础相关的东西,对vue基础的使用和js基本算法的都有很大的帮助。
  • 代码可能有些复杂和繁琐,但只要逻辑思路清晰,实现起来基本没有问题。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值