Vue結(jié)合Element-Plus封裝遞歸組件實(shí)現(xiàn)目錄示例
前言
在寫我的個(gè)人博客網(wǎng)站,用MarkDownIt將md解析成html時(shí),我一直在想,怎么才能實(shí)現(xiàn)官方文檔他們那些可折疊的目錄結(jié)構(gòu)呢?我有那么多標(biāo)題(h1...h5),而且有的文章是只有h2或者h(yuǎn)3的,難道我要在目錄組件里面一個(gè)個(gè)v-if來渲染這些標(biāo)題達(dá)到目錄的效果嘛?這個(gè)問題在我某一天看vue文檔的時(shí)候得到了解決。如下。

沒錯(cuò),遞歸組件可以解決我這個(gè)困惑,遞歸無非就是自己調(diào)用自己,我們編寫好合理的組件渲染邏輯之后,在組件內(nèi)部自己調(diào)用自己,這就是遞歸組件,接下來請(qǐng)看我的解決步驟吧!
用正則匹配出所有的h標(biāo)簽并且保存在數(shù)組中
//這里的str是用MarkdownIt解析生成的html字符串 const menu = [...str.matchAll(/<h.*>.*</h.>/g)]
效果如下

封裝函數(shù),將數(shù)組中的內(nèi)容變成父子結(jié)構(gòu)
//我的每個(gè)菜單的類型
class menuItem {
title: string
children?: menuItem[]
type: number //type為1表示是h1標(biāo)簽
index: number //index表示是type對(duì)應(yīng)的第幾個(gè)h標(biāo)簽
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標(biāo)簽
const arr: menuItem[] = []
const arrIndex: number[] = new Array(7).fill(0)
// 用于保存前一個(gè)層的結(jié)點(diǎn)。例如我當(dāng)前遍歷的是type=3的item,那么我需要知道它所屬于哪個(gè)type=2的item
// 如果有就添加到它的children中,如果沒有就添加到pre[3]中
const pre = new Array(7).fill(null)
//記錄h min是哪個(gè)標(biāo)簽(例如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]++)
//判斷當(dāng)前type-1項(xiàng)有沒有內(nèi)容,有的話就加入到前一個(gè)種類的children中去
if (pre[type - 1]) {
pre[type - 1].children.push(menuitem)
}
//重置當(dāng)前type的項(xiàng)
pre[type] = menuitem
minType = minType ?? type
//如果是最小的h標(biāo)簽,就插入
if (type === minType) {
arr.push(menuitem)
}
}
return arr
}轉(zhuǎn)換的arr結(jié)果如下,可以看到,數(shù)組中保存了兩個(gè)頂層目錄,children保存了內(nèi)部的子目錄。

封裝遞歸組件fold-item(在使用之前不要忘了導(dǎo)入自己哦)
<script lang="ts" setup>
import foldItem from './foldItem.vue' //導(dǎo)入自己
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>使用效果

更復(fù)雜的目錄結(jié)構(gòu)也能勝任

到此這篇關(guān)于Vue結(jié)合Element-Plus封裝遞歸組件實(shí)現(xiàn)目錄示例的文章就介紹到這了,更多相關(guān)Vue Element-Plus遞歸目錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue項(xiàng)目中頁(yè)面底部出現(xiàn)白邊及空白區(qū)域錯(cuò)誤的問題
這篇文章主要介紹了vue項(xiàng)目中頁(yè)面底部出現(xiàn)白邊及空白區(qū)域錯(cuò)誤的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
使用Vue3和Echarts?5繪制帶有立體感流線中國(guó)地圖(推薦收藏!)
最近接到一個(gè)需求是做一個(gè)中國(guó)地圖,下面這篇文章主要給大家介紹了關(guān)于如何使用Vue3和Echarts?5繪制帶有立體感流線中國(guó)地圖的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04
vue.js移動(dòng)數(shù)組位置,同時(shí)更新視圖的方法
下面小編就為大家分享一篇vue.js移動(dòng)數(shù)組位置,同時(shí)更新視圖的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-03-03
vue實(shí)現(xiàn)未登錄跳轉(zhuǎn)到登錄頁(yè)面的方法
這篇文章主要介紹了vue實(shí)現(xiàn)未登錄跳轉(zhuǎn)到登錄頁(yè)面的方法,主要目的是實(shí)現(xiàn)未登錄跳轉(zhuǎn),需要的朋友參考下吧2018-07-07
Vue + Echarts頁(yè)面內(nèi)存占用高的問題解決方案
點(diǎn)擊左側(cè)的菜單可以切換不同的看板,有些看板頁(yè)面中的報(bào)表比較多,用戶多次切換后頁(yè)面的內(nèi)存占用可以上升為GB級(jí),嚴(yán)重時(shí)導(dǎo)致頁(yè)面內(nèi)存溢出,使得頁(yè)面崩潰,極大影響了用戶體驗(yàn),本文給大家介紹Vue + Echarts頁(yè)面內(nèi)存占用高的問題解決方案,感興趣的朋友一起看看吧2024-02-02
vue實(shí)現(xiàn)點(diǎn)擊關(guān)注后及時(shí)更新列表功能
這篇文章主要介紹了vue實(shí)現(xiàn)點(diǎn)擊關(guān)注后及時(shí)更新列表功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-06-06
VUE2響應(yīng)式原理使用Object.defineProperty缺點(diǎn)
這篇文章主要為大家介紹了VUE2響應(yīng)式原理使用Object.defineProperty缺點(diǎn)示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08

