当前位置:   article > 正文

Vue3---手写Tree组件_vue3 树组件

vue3 树组件

Vue3---手写Tree组件

首先我们分析数据的结构

treeOptions:[
   {
      lable:'一级',
      children:[
          {
             lable:'一级-1'
          },
          {
             lable:'一级-2'
          }
      ]
   },
   {
      lable:'二级',
      children:[
          {
             lable:'二级-1',
             children:[
                {
                 lable:'二级-1-1'
                },
                {
                 lable:'二级-1-2'
                }
             ]
          },
          {
             lable:'二级-2'
          }
      ]
   },
   {
      lable:'三级'
   }
  ]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

对于这种数组类型的取值,首先想到的是v-for,但是我们不能准确的知道需要使用多少个v-for。如果所有的子项中children的层级是一样的(比如下面的情况),那可以使用。但是问题是现在的数据有的item会有4层的children,有的item会有10层的children,层级不一样,这个时候,我们可以考虑递归

// 数据的格式
// 如果是这种类型的,我们可以使用v-for进行渲染,写两层v-for。label就渲染出来了。 
treeOptions:[
   {
      lable:'一级',
      children:[
          {
             lable:'一级-1'
          },
          {
             lable:'一级-2'
          }
      ]
   },
   {
      lable:'二级',
      children:[
          {
             lable:'二级-1'
          },
          {
             lable:'二级-2'
          }
      ]
   },
   {
      lable:'三级',
      children:[
          {
             lable:'三级-1'
          },
          {
             lable:'三级-2'
          }
      ]
   }
]




// 但是这样的数据结构,没法知道具体用几个v-for,这个时候,我们可以考虑用递归的方式解决问题。
treeOptions:[
   {
      lable:'一级',
      children:[
          {
             lable:'一级-1'
          },
          {
             lable:'一级-2'
          }
      ]
   },
   {
      lable:'二级',
      children:[
          {
             lable:'二级-1',
             children:[
                {
                 lable:'二级-1-1'
                },
                {
                 lable:'二级-1-2'
                }
             ]
          },
          {
             lable:'二级-2'
          }
      ]
   },
   {
      lable:'三级'
   }
]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

步骤:

  1. 定义Tree组件,并挂载到全局上,方便自己调用自己
    在这里插入图片描述

在这里插入图片描述

  1. 书写Tree组件
// Tree.vue
<template>
  <li v-for="(item,index) in Options" :key="index">
    {{ item.lable }}
    <!-- 当没有children的时候,就不用走递归了。-->
    <ul v-if="item.children&&item.children.length">
      <MyTree :options="item.children"></MyTree>
    </ul>
  </li>
</template>

<script setup>

import {ref} from "vue";

const prop = defineProps({
  options: {
    type: Array,
    default: () => {
      return []
    }
  }
})

//console.log(prop.options)
</script>

<style scoped>

</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
// App.vue
<template>
  <h5>树型组件</h5>
  <Mtree :options="treeOptions" />
</template>

<script setup>
import {reactive} from "vue";

const state = reactive({
  treeOptions:[
   {
      lable:'一级',
      children:[
          {
             lable:'一级-1'
          },
          {
             lable:'一级-2'
          }
      ]
   },
   {
      lable:'二级',
      children:[
          {
             lable:'二级-1',
             children:[
                {
                 lable:'二级-1-1'
                },
                {
                 lable:'二级-1-2'
                }
             ]
          },
          {
             lable:'二级-2'
          }
      ]
   },
   {
      lable:'三级'
   }
   ]
})

const { treeOptions } = state
</script>

<style scoped>

</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  1. 添加点击后展开,再点击折叠的功能
=<template>
  <li v-for="(item,index) in myOptions" :key="index" @click.stop="openUl(item)">
    {{ item.lable }}
    <!-- 当没有children的时候,就不用走递归了。-->
    <ul v-if="item.children&&item.children.length" v-show="item.isOpen">
      <MyTree :options="item.children"></MyTree>
    </ul>
  </li>
</template>

<script setup>
/*
重点:通过isOpen属性的true,false,来使组件是否v-show隐藏显示

方法:
  1  添加myOptions ,使之双向绑定,绑定的数据来自prop.options传来的数据,不直接用prop.options传来数据的原因是因为要加isOpen,防止原数据遭到污染。
  const myOptions = ref(prop.options);

 2  在递归组件上添加v-show="item.isOpen"   用于显示与隐藏

 3 在根组件上添加 @click.stop="openUl(item)"
   	const openUl= (item)=>{
  		item.isOpen = !item.isOpen
	}

    加上.stop为了防止事件冒泡
* */
import {ref} from "vue";

const prop = defineProps({
  options: {
    type: Array,
    default: () => {
      return []
    }
  }
})

//console.log(prop.options)

/*
* 点击以后,展开ul,再点击,关闭ul
* */

const myOptions = ref(prop.options);
const openUl= (item)=>{
  item.isOpen = !item.isOpen
}
</script>

<style scoped>

</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

关于使用v-for 和 递归时候,数据是怎么渲染出来的分析。

// v-for的形式
  treeOptions:[
   {
      lable:'一级',
      children:[
          {
             lable:'一级-1',
             //......下面有1万层children
          }
      ]
   },
   {
      lable:'二级',
      children:[
          {
             lable:'二级-1',
             //......下面有1万层children
          }
      ]
   }
   ]



// 使用v-for的写法:

<div v-for='(item,index) in Data'>
  <div v-for='(childItem,childIndex) in item.children'>
     ......  
  </div>
</div>

这个时候会先渲染 "一级" ,再渲染"一级-1""一级-1-1"......  "一级-1-1...-10000"

紧接着:"二级" ,再渲染"二级-1""二级-1-1"......  "二级-1-1...-10000"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  // 递归的形式
  treeOptions:[
   {
      lable:'一级',
      children:[
          {
             lable:'一级-1',
             //......下面有1万层children
          }
      ]
   },
   {
      lable:'二级',
   }
   ]


// 这个时候,如果使用v-for就不行了。为了渲染item1,需要写10000个v-for,但是item2只需要写一个v-for。

// 这个时候,递归发挥作用了,每次都是自己调用自己,传入的值总是children。当children没有的时候,再渲染item2,也就是"二级"
这个时候会先渲染 "一级" ,再渲染"一级-1""一级-1-1"......  "一级-1-1...-10000"
再渲染 "二级"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/119270
推荐阅读
相关标签
  

闽ICP备14008679号