前言:
之前在使用element-plus的使用,使用el-menu组件,并且使用了递归思想完成了无限极菜单的展开,现在想要自己手写一个简单的树形组件,同样使用递归的思想
全局注册组件
文件结构:
---mTree ---index.ts ---mTree.vue
在index.ts文件中引入组件然后注册,并最后在main.ts文件中引入并且使用app.use
import mTree from "./mTree.vue" mTree.install = app => { app.component(mTree.name,mTree) } export default mTree
组件的实现🥊🥊
首先我们先要创建一个树状的数据,分清楚层级关系
const state = reactive({ treeOptions: [ { label: '一级', children: [ ... { label: '一级-3', children: [ .... ], }, ], }, ... })
就像这样的层级关系,当然这里面我们只是模拟数据,真实的项目开发过程中应该是后端给前端数据,然后前端在根据数据进行渲染
树形组件的基本结构:
<template> <li v-for="item in options" :key="item.label"> {{ item.label }} <ul v-if="item.children&&item.children.length>0"> <mTree :options="item.children"></mTree> </ul> </li> </template>
如图:
解释一下这个组件的这个结构:
首先使用li组件渲染第一层结构,然后在ul里面重新嵌套mTree树形组件,并且判断当前item元素是否有children属性,如果有这个属性,那么就进行渲染,否则的话就不渲染。这样就不停的递归,到最后一个children都渲染结束之后结束了。这样在不确定有多少层级时就可以使用,可以实现无限的层级嵌套。
完善组件(添加点击事件,过渡效果)✌️✌️
<li v-for... @click.stop="toggleisOpen(item)"> {{ item.label }} <transition name="slide-fade"> <ul v-show="item.isOpen">...</ul> </transition> </li>
这里只展示了新增的代码,给li添加了一个点击事件:
interface optionsProp { label: string isOpen?: boolean children?: optionsProp[] } const props = defineProps({ options: { type: Array as PropType<optionsProp[]>, default() { return [] }, }, }) const toggleisOpen = (item: any) => { item.isOpen = !item.isOpen }
注意ul通过v-show来控制显示或者隐藏,当第一次点击的时候由于源数据中没有isOpen,所以这个时候取反就是true,就会显示点击元素的子级。还有一点要注意的时,由于冒泡会导致出现一些问题,所以在点击事件后面加上.stop来阻止冒泡。
添加过渡
这里我们使用了Vue3官方中的过渡,不是很了解的小伙伴可以去官网查看,简单来说就是使用transition包裹要使用过渡效果的部分,然后定义name属性,本文中的name为slide-fade所以下面的样式就是这样的:
v-enter-from
:进入动画的起始状态。
v-enter-active
:进入动画的生效状态。
v-leave-active
:离开动画的生效状态
v-leave-to
:离开动画的结束状态。
.slide-fade-enter-active { transition: all 0.3s ease-out; } .slide-fade-leave-active { transition: all 0.2s cubic-bezier(1, 0.5, 0.8, 1); } .slide-fade-enter-from, .slide-fade-leave-to { transform: translateY(20px); opacity: 0; }
总结:
通过对这个组件的实现,我们有掌握了对递归组件的使用以及简单的实现,学习的时候可以对自己好奇的东西尝试自己去实现,这样做我们可以学习的更快,并且使自己有一些小小的成就感。