首先我們要知道,既然是遞歸組件,那么一定要有一個結束的條件,否則就會使用組件循環引用,最終出現“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>