Vue元件化開發的必備技能之元件遞迴
目錄
- 前言
- 效果展示
- 渲染完整資料
- 效果如下
- 獲取節點資料
- 效果如下
- 動態展開收起
- 效果如下
- 完整程式碼
- 效果如下
- 總結
前言
不知道大家有沒遇到過這樣的場景:渲染列表資料的時候,列表的子項還是列表。如果層級少尚且可以用幾個for迴圈搞定,但是層級多或者層級不確定就有點無從下手了。
其實這就是樹形結構資料,像常見的組織架構圖,資料夾目錄,導航選單等都屬於這種結構。很多元件庫都帶有樹形元件,但往往樣式不是我們想要的,改起來也非常的費勁。那麼,如何自己渲染這些資料呢?答案就是——元件遞迴!
效果展示
以上就是使用元件遞迴,並加入簡單互動的展示效果。點選節點會在控制檯輸出節點對應的資料,如果有子節點,則會展開或收起子節點。接下來我們就看看如何實現以上效果吧!
渲染完整資料
渲染資料這一步非常簡單,首先是把樹形結構封裝成一個列表元件,其次判斷每一項有沒有子節點,如果有子節點,再使用自身元件去渲染就可以了。
src/components/myTree.
<template> <div class="tree-item"> <div v-for="item in treeData" :key="item.id"> <div class="item-title">{{ item.name }}</div> <div v-if="item.children && item.children.length" class="item-childen"> <my-tree :treeData="item.children"></my-tree> </div> </div> </div> </template> <script> export default { name: 'myTree',props: { treeData: { type: Array,default: () => [] } } } </script> <style lang="s" scoped> .tree-item { .item-title { padding: 4px 8px; } .item-childen { padding-left: 20px; } } </style>
src/App.vue
<template> <my-tree :tree-data="treeData"></my-tree> </template> <script> const treeData = [ { id: 1,name: '一級1' },{ id: 2,name: '一級2',children: [ { id: 3,name: '二級2-1' },{ id: 4,name: '二級2-2' } ] },{ id: 5,name: '一級3',children: [ { id: 6,name: '二級3-1',children: [ { id: 7,name: '三級3-1-1' },{ id: 8,name: '三級3-1-2' } ] },{ id: 9,name: '二級3-2' },{ id: 10,name: '二級3-3' } ] } ] import myTree from '@/components/myTree.vue' export default { components: { myTree },data() { return { treeData: treeData } } } </script>
效果如下
獲取節點資料
接下來我們要做的是,點選節點時在控制檯輸出對應的資料。首先我們使用 $emit,將一級節點的 item 傳遞出去,也就是子傳父的方法,相信大家都會。
其次是將內層節點的資料傳遞出去,同樣使用子傳父的方法,只是我們需要給元件裡面的 my-tree 繫結@node-click="$emit('node-click',$event)"
,這樣每次子級每次都可以呼叫父級的 node-click 方法,父級又呼叫它的父級 node-click 方法,最終調的都是最外層的 node-click 方法,我們只需要在這個過程中,把資料傳遞過去就可以了。這塊有點繞,相信大家多看幾遍應該可以看懂。修改如下:
src/components/myTree.vue
<div class="item-title" @click="itemNodeClick(item)">{{ item.name }}</div> <div v-if="item.children && item.children.length" class="item-childen"> <my-tree :treeData="item.children" @node-click="$emit('node-click',$event)" ></my-tree> </div> ... itemNodeClick(item) { this.$emit("node-click",item) }
src/App.vue
<my-tree :tree-data="treeData" @node-click="nodeClick"></my-tree> ... nodeClick(val) { console.log(val) }
效果如下
動態展開收起
這一步的思路是給元件設定一個數組,陣列中存放的是當前列表中需要展開的節點的id,當點選節點的時候新增或刪除節點id,然後判斷每個節點的id在不在這個陣列,在則顯示子節點,不在則隱藏子節點。
src/components/myTree.vue
<div class="item-title" @click="nodeClick(item)"> <span>{{ item.name }}</span> <span v-if="item.children && item.children.length"> [{{ isOpen(item.id) ? '-' : '+' }}] </span> </div> <div v-if="item.children && item.children.length" v-show="isOpen(item.id)" class="item-childen" > <my-tree :treeData="item.children" @node-click="$emit('node-click',$event)" ></my-tree> </div> ... data() { return { expandedKeys: [] // 當前列表需要展開的節點id組成的陣列 } },methods: { nodeClick(item) { this.$emit('node-click',item) if (item.children && item.children.length) { let index = this.expandedKeys.indexOf(item.id) if (index > -1) { // 如果當前節點id存在陣列中,則刪除 this.expandedKeys.splice(index,1) } else { // 如果當前節點id不存在陣列中,則新增 this.expandedKeys.push(item.id) } } },isOpen(id) { // 判斷節點id在不在陣列中,在則顯示,不在則隱藏 return this.expandedKeys.includes(id) } }
效果如下
最後我們再新增一些樣式,就大功告成啦!
完整程式碼
src/components/myTree.vue
<template>
<div class="tree-item">
<div v-for="item in treeData" :key="item.id">
<div class="item-title" @click="nodeClick(item)">
<span>{{ item.name }}</span>
<span v-if="item.children && item.children.length">
www.cppcns.com [{{ isOpen(item.id) ? '-' : '+' }}]
</span>
</div>
<div
v-if="item.children && item.children.length"
v-show="isOpen(item.id)"
class="item-childen"
>
<my-tree
:treeData="item.children"
@node-click="$emit('node-click',$event)"
>&http://www.cppcns.comlt;/my-tree>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'myTree',default: () => []
}
},data() {
return {
expandedKeys: [] // 當前展開的節點id組成的陣列
}
},methods: {
nodeClick(item) {
this.$emit('node-click',item)
if (item.children && item.children.length) {
let index = this.expandedKeys.indexOf(item.id)
if (index > -1) {
// 如果當前節點id存在陣列中,則刪除
thiwww.cppcns.coms.expandedKeys.splice(index,1)
} else {
// 如果當前節點id不存在陣列中,則新增
this.expandedKeys.push(item.id)
}
}
},isOpen(id) {
// 判斷節點id在不在陣列中,在則顯示,不在則隱藏
return this.expandedKeys.includes(id)
}
}
}
</script>
<style lang="scss" scoped>
.tree-item {
cursor: pointer;
.item-title {
padding: 4px 8px;
&:hover {
background: #eee;
}
}
.item-childen {
padding-left: 20px;
}
}
</style>
src/App.vue
<template> <my-tree :tree-data="treeData" @node-click="nodeClick"></my-tree> </template> <script> const treeData = [ { id: 1,data() { return { treeData: treeData } },methods: { nodeClick(val) { console.log(val) } } } </script>
效果如下
以上就是今天的分享!有興趣的小夥伴可以動手試一哈,把元件進一步封裝,或修改成自己想要的樣式。 Vue官方的樹形檢視:cn.vue.org/v2/examples…
總結
到此這篇關於Vue元件化開發的必備技能之元件遞迴的文章就介紹到這了,更多相關Vue元件遞迴內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!