首先我們要知道,既然是遞歸組件,那么一定要有一個結束的條件,否則就會使用組件循環引用,最終出現“max stack size exceeded”的錯誤,也就是棧溢出。那么,我們可以使用v-if="判斷條件"作為遞歸組件的結束條件。當遇到v-if為false時,組件將不會再進行渲染
1. 准備一個樹狀的遞歸數據 這里演示一個側邊欄組件
navigation: [ { types: 1, id: "0", name: "首頁", path: "/jiaowu_system/home", icon: "icon_hrIndex.png", children: [] }, { types: 1, id: "1", name: "教學資源", path: "", icon: "jiaowu_system_jiaoxueziyuan.png", children: [ { types: 2, id: "1 - 1", name: "學校信息", path: "/jiaowu_system/SchoolInformation", icon: "", children: [] }, { types: 2, id: "1 - 2", name: "管理部門信息", path: "/jiaowu_system/administration", icon: "", children: [] } ] }, { types: 1, id: "2", name: "教學計划", path: "", icon: "jiaowu_system_jihua.png", children: [] }
]
2. 創建一個簡單的遞歸組件
// 這里 我是通過name實現遞歸效果的 你可以把它當作從import導入了一個組件並注冊,我們在temlpate可以使用<list-menu></list-menu>使用子組件自身進行遞歸了 默認不展示子組件,只能在父組件點擊的時候才會展示 使用的 v-show 減少渲染消耗
<template>
<div class="list">
<div @click.prevent="handleClick">
{{ model.name }}
</div>
<div v-show="reveal" v-if="isDispaly" style="margin-left:20px;">
<list-menu v-for="item in model.children" :key="item.id" :model="item" />
</div>
</div>
</template>
<script>
export default {
name: "listMenu",
components: {},
props: ["model"],
data() {
return {
reveal: false
};
},
methods: {
handleClick() {
if (this.isDispaly) {
this.reveal = !this.reveal;
}
}
},
computed: {
isDispaly() {
return this.model.children && this.model.children.length;
}
}
};
</script>
<style scoped>
div {
width: 100px;
margin: 20px 0;
}
</style>
上述代碼中我們需要注意,這個組件必須含有 name 這個屬性,因為沒有 name 這個屬性會造成控件自身不能調用自身, 當使用它時,只需要把上邊我們定義好的數據通過props的方式傳進去即可
3. 我們創建一個sidebar組件,這個組件作為使用遞歸組件的父組件
// navigation的數據在上面 需要copy
<template>
<div class="sidebar">
<div v-for="menu in navigation" :key="menu.id">
<list-menu :model="menu"></list-menu>
</div>
</div>
</template>
<script>
import listMenu from "./list";
export default {
name: "sidebar",
components: {
listMenu
},
props: {},
data() {
return {
navigation: [] // 數據太長 就不在這里面寫了
};
}
};
</script>
好了 我們就實現了一個簡單的遞歸側邊欄組件,這段代碼只是簡單的做了下遞歸組件的使用。對於折疊樹狀菜單來說,我們一般只會去渲染一級的數據,當點擊一級菜單時,再去渲染一級菜單下的結構,如此往復。那么v-if就可以實現我們的這個需求,當v-if設置為false時,遞歸組件將不會再進行渲染,設置為true時,繼續渲染。組件中的name不僅可以遞歸的時候使用 還可以當項目使用keep-alive時,可搭配組件name進行緩存過濾
一個簡單的小實例
<div id="app">
<keep-alive exclude="Detail">
<router-view/>
</keep-alive>
</div>
