Vue结合Element-Plus封装递归组件实现目录示例
短信预约 -IT技能 免费直播动态提醒
前言
在写我的个人博客网站,用MarkDownIt将md解析成html时,我一直在想,怎么才能实现官方文档他们那些可折叠的目录结构呢?我有那么多标题(h1...h5),而且有的文章是只有h2或者h3的,难道我要在目录组件里面一个个v-if来渲染这些标题达到目录的效果嘛?这个问题在我某一天看vue文档的时候得到了解决。如下。
没错,递归组件可以解决我这个困惑,递归无非就是自己调用自己,我们编写好合理的组件渲染逻辑之后,在组件内部自己调用自己,这就是递归组件,接下来请看我的解决步骤吧!
用正则匹配出所有的h标签并且保存在数组中
//这里的str是用MarkdownIt解析生成的html字符串
const menu = [...str.matchAll(/<h.*>.*</h.>/g)]
效果如下
封装函数,将数组中的内容变成父子结构
//我的每个菜单的类型
class menuItem {
title: string
children?: menuItem[]
type: number //type为1表示是h1标签
index: number //index表示是type对应的第几个h标签
constructor(
title: string,
type: number,
index: number,
children: menuItem[] = []
) {
this.title = title
this.children = children
this.type = type
this.index = index
}
}
export default function (menu: any[]): any[] {
//保存所有h min标签
const arr: menuItem[] = []
const arrIndex: number[] = new Array(7).fill(0)
// 用于保存前一个层的结点。例如我当前遍历的是type=3的item,那么我需要知道它所属于哪个type=2的item
// 如果有就添加到它的children中,如果没有就添加到pre[3]中
const pre = new Array(7).fill(null)
//记录h min是哪个标签(例如h1)
let minType = null
for (const item of menu) {
const content = item[0]
const type = parseInt(content[2])
const title = content.split(/<\/?h.>/)[1]
const menuitem = new menuItem(title, type, arrIndex[type]++)
//判断当前type-1项有没有内容,有的话就加入到前一个种类的children中去
if (pre[type - 1]) {
pre[type - 1].children.push(menuitem)
}
//重置当前type的项
pre[type] = menuitem
minType = minType ?? type
//如果是最小的h标签,就插入
if (type === minType) {
arr.push(menuitem)
}
}
return arr
}
转换的arr结果如下,可以看到,数组中保存了两个顶层目录,children保存了内部的子目录。
封装递归组件fold-item(在使用之前不要忘了导入自己哦)
<script lang="ts" setup>
import foldItem from './foldItem.vue' //导入自己
defineProps({
item: {
type: Object,
default: () => ({})
}
})
</script>
<template>
<!-- 如果有孩子,就渲染成sub-menu(折叠item)-->
<template v-if="item.children.length">
<el-sub-menu :index="item.title">
<template #title>
<div class="title" v-html="item.title"></div>
</template>
<fold-item
v-for="i in item.children"
:key="i.title"
:item="i"
></fold-item>
</el-sub-menu>
</template>
<!-- 否则就渲染成menu-item-->
<template v-else>
<el-menu-item :index="item.title" @click="scrollToItem(item)">
<template #title>
<div class="title" v-html="item.title"></div>
</template>
</el-menu-item>
</template>
</template>
<style lang="less" scoped>
.title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
::v-deep.el-menu-item {
width: 220px;
line-height: 30px;
height: 30px;
}
::v-deep.el-sub-menu {
width: 220px;
}
::v-deep .el-sub-menu__title {
height: 30px;
line-height: 30px;
}
</style>
在foldMenu中使用递归组件
<script lang="ts" setup>
import foldItem from './foldItem.vue'
defineProps({
menu: {
type: Array,
default: () => []
}
})
</script>
<template>
<div class="menu-title">目录</div>
<el-menu>
<!-- 使用递归组件 -->
<fold-item v-for="item in menu" :key="item.title" :item="item"></fold-item>
</el-menu>
</template>
<style lang="less" scoped>
::v-deep.el-menu {
border: none;
}
.menu-title {
text-align: center;
margin-bottom: 10px;
}
</style>
使用效果
更复杂的目录结构也能胜任
到此这篇关于Vue结合Element-Plus封装递归组件实现目录示例的文章就介绍到这了,更多相关Vue Element-Plus递归目录内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341