遞歸函數我們都再熟悉不過了,也就是函數自己調用自己。遞歸組件也是類似的,在組件的template內部使用組件自身。那遞歸組件有什么使用場景呢? 我們都知道樹這個數據結構就是一種遞歸的結構,因此我們可以用遞歸組件去實現一個Tree效果,一般可以用於多層級的菜單。
首先是我們的Tree組件,它包含n個TreeNode(樹的節點),也就是一級的菜單項。(注: treeData數據摘取自ElementUI的樹形組件示例)
<template> <div id="app"> <!-- 一級菜單列表--> <ul> <TreeNode v-for="nodeData in treeData" :nodeData="nodeData" :key="nodeData.label"></TreeNode> </ul> </div> </template> <script> import TreeNode from '../components/TreeNode' export default { name: 'Tree', components: { TreeNode }, data () { return { treeData: [ { label: '一級 1', children: [{ label: '二級 1-1', children: [{ label: '三級 1-1-1' }] }] }, { label: '一級 2', children: [{ label: '二級 2-1', children: [{ label: '三級 2-1-1' }] }, { label: '二級 2-2', children: [{ label: '三級 2-2-1' }] }] }, { label: '一級 3', children: [{ label: '二級 3-1', children: [{ label: '三級 3-1-1' }] }, { label: '二級 3-2', children: [{ label: '三級 3-2-1' }] }] }] } } } </script>
然后我們來實現TreeNode組件。
<template> <li> <!-- 菜單項標題和展開/收起按鈕--> <div> <span>{{nodeData.label}}</span> <span v-if="hasChild" @click="open = !open">[{{open ? '-' : '+'}}]</span> </div> <!-- 子菜單 --> <ul v-show="open" v-if="hasChild"> <TreeNode v-for="childNodeData in nodeData.children" :nodeData="childNodeData" :key="childNodeData.label"></TreeNode> </ul> </li> </template> <script> export default { // 必須要寫name, 否則在組件內部使用TreeNode標簽將無法解析 name: 'TreeNode', props: ['nodeData'], data: function () { return { // 標識展開/收起狀態 open: false } }, computed: { // 是否有子菜單 hasChild: function () { return this.nodeData.children && this.nodeData.children.length } } } </script> <style scoped> span { font-size: 36px; } </style>
我們都知道,一級菜單下面可能還包含多個二級菜單,二級菜單下面可能包含多個三級菜單,以此類推...因此,在TreeNode組件的template中我們再次使用了TreeNode組件,從而形成了遞歸組件。
運行效果如下,點擊 + / - 號按鈕可以實現展開和收起: