Tree 元件是遞迴類元件的典型代表,它常用於資料夾、組織架構、生物分類、國家地區等等,世間萬物的大多數結構都是樹形結構。使用樹控制元件可以完整展現其中的層級關係,並具有展開收起選擇等互動功能。
如圖所示,我們要實現的就是這樣一個效果。之前我們寫樹狀結構都是用jQuery來實現的,用Vue怎麼實現呢?
一、資料部分模擬
menuList:[
{
title:'選單1',
children:[
{
title:'選單1-1',
children:[
{title:'選單1-1-1'},
{title:'選單1-1-2'},
{title:'選單1-1-3'}
]
},
{title:'選單1-2'},
{title:'選單1-3'}
]
},
{title:'選單2'},
{title:'選單3'}
]
複製程式碼
二、元件各部分實現
Menu.vue
首先我們來寫個menu元件,這裡放個ul列表,裡面的內容,用插槽來表示。
<template>
<ul>
<slot></slot>
</ul>
</template>
<script>
export default {
name: "Menu"
}
</script>
複製程式碼
MenuItem.vue
如果沒有子節點,所要展示的標題
<template>
<li><slot></slot></li>
</template>
<script>
export default {
name: "MenuItem"
}
</script>
複製程式碼
SubMenu.vue
<template>
<div>
<div class="title" @click="change">
<slot name="title"></slot>
<!--name='title'區分插槽 -->
</div>
<div class="sub" v-show="flag">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: "SubMenu",
data(){
return {flag:false}
},
methods:{
change(){
this.flag=!this.flag
}
}
}
</script>
<style>
.sub{
padding-left:20px;
}
</style>
複製程式碼
三、遞迴元件ReSubMenu.vue
這裡到了我們實現樹形結構思想的重點,即遞迴元件。當我們重複判斷有沒有子節點,並做出相應的展示的時候,這裡就可以使用遞迴元件了。方便快捷,你值得擁有。
由於有子節點會迴圈SubMenu這部分操作,所以單獨提出來放到ReSubMenu元件中
<template>
<SubMenu>
<template #title><!--#title為了標識區分插槽-->
{{data.title}}
</template>
<template v-for="child in data.children">
<MenuItem :key="child.title" v-if="!child.children">{{child.title}}</MenuItem>
<!--ReSubMenu跟name的名字保持一致,相當於迴圈使用該元件-->
<ReSubMenu v-else :key="child.title" :data="child"></ReSubMenu>
</template>
</SubMenu>
</template>
<script>
import SubMenu from './SubMenu'
import MenuItem from './MenuItem'
export default {
name: "ReSubMenu",//可以使用遞迴元件
props:{
data:{
type:Object,//屬性校驗,為物件資料型別,並且如果沒有賦值,預設給一個空物件
default:()=>({})
}
},
components:{
SubMenu,
MenuItem
}
}
</script>
複製程式碼
四、整合實現
<div id="app">
<Menu>
<template v-for="menu in menuList">
<MenuItem :key="menu.title" v-if="!menu.children">{{menu.title}}</MenuItem>
<!--這部分是如果有孩子節點則會迴圈這部分操作,所以要單獨提取出來-->
<!-- <SubMenu v-else>
<template #title>{{menu.title}}</template>
<template v-for="child in menu.children">
<MenuItem>{{child.title}}</MenuItem>
</template>
</SubMenu>-->
<ReSubMenu :key="menu.title" v-else :data="menu"></ReSubMenu>
</template>
</Menu>
<div>
<script>
import Menu from './Menu'
import MenuItem from './MenuItem'
// import SubMenu from './SubMenu'
import ReSubMenu from './ReSubMenu'
export default {
data(){
return{
//這裡的資料我就模擬一個了
menuList:[
{
title:'選單1',
children:[
{
title:'選單1-1',
children:[
{title:'選單1-1-1'},
{title:'選單1-1-2'},
{title:'選單1-1-3'}
]
},
{title:'選單1-2'},
{title:'選單1-3'}
]
},
{title:'選單2'},
{title:'選單3'}
]
}
},
components:{
Menu,MenuItem,ReSubMenu
}
}
</script>
複製程式碼
注:本節部分語句參考 https://juejin.im/book/5bc844166fb9a05cd676ebca/section/5bfcecc7f265da61682b102a
。