做者:Milos Protic前端
譯者:前端小智vue
來源:vuejsdevelopersgit
你知道的越多,你不知道的越多
github點贊再看,養成習慣
面試
本文 GitHub:github.com/qq449245884… 上已經收錄,更多往期高贊文章的分類,也整理了不少個人文檔,和教程資料。歡迎Star和完善,你們面試能夠參照考點複習,但願咱們一塊兒有點東西。bash
有人說遞歸很難理解,也有人不這麼認爲。遞歸函數簡單的定義是:一個自調用函數,這意味着它將在執行的某個時刻調用本身。微信
從理論上講,遞歸是一種須要兩個屬性的行爲:數據結構
我們沒法決定哪個更重要。若是沒有結束點,遞歸將成爲一個無限循環,可是若是一組規則就不能實現指望的行爲,因此二者都存在才能使它正常工做。app
在 Vue 中,遞歸很是有用。固然,不只僅在 Vue 中,我們能夠遵循上面的規則在任何框架中實現遞歸行爲。所以,根據給定的定義,我們能夠說遞歸組件是調用自身的組件。框架
遞歸組件何時有用? 只要我們須要使用相同的模板結構,但須要使用分層輸入數據,就可使用遞歸。 若是樹狀視圖(用於顯示文件夾結構),網站上的註釋,嵌套菜單等組件等等。
接着,我們創建一個場景來演示遞歸組件的用途。
想象一下,咱像往常同樣來上班,給本身衝杯咖啡,開始閱讀咱最喜歡的博客。忽然,我們的老闆來了,說須要實現一個新的頁面,在這個頁面上,顯示全部的文件夾、子文件夾和文件,且文件結構數量不肯定。能夠顯示10
個、5
個或100
個文件夾。接着,我們喝着咖啡,開始撓頭思考如何解決這個問題。最終,我們會想到使用遞歸遍從來實現。
解決這個問題的組件的最少數量是1
,但在我們的示例中,我們會建立兩個組件:
root
組件folder
組件固然,我們首先搞點數據來用:
如前所述,當我們有分層組織的數據,其中子數據具備與其父數據相同的結構時,遞歸就派上用場了。
const root = {
text: 'Root Folder',
leaf: false,
expanded: true,
children: [{
text: 'Sub Folder 1',
leaf: false,
expanded: false,
children: [{
text: 'Sub Sub Folder 1',
leaf: false,
expanded: false,
children: [{
text: 'SomeFile1.js',
leaf: true
}]
}, {
text: 'Sub Sub Folder 2',
leaf: false,
expanded: false,
children: []
}, {
text: 'SomeFile.txt',
leaf: true
}]
}]
}
複製代碼
有了上面的數據,我們開始建立組件。
這個組件是我們文件夾樹的起點。它會開始全部子元素的沉浸,可是若是須要,它也能夠顯示一些獨立的信息,由於它不是遞歸自己的一部分。
root
組件將包含一個folder
屬性,我們會把root
數據對象綁定到該屬性上。此屬性將傳遞給子組件,子組件將遞歸地建立基於它的文件夾樹結構。
Template
<template>
<ul class="folders">
<li>Folders</li>
<folder v-bind:folder="folder"></folder>
</ul>
</template>
複製代碼
代碼
import Folder from './Folder.vue';
export default {
name: 'root',
props: {
folder: Object
},
components: {
Folder
}
};
複製代碼
樣式
ul.folders {
padding: 1rem;
margin: 0;
box-sizing: border-box;
width: 100%;
list-style: none
}
ul.folders > li:first-child {
padding: 1rem 1rem 1rem 0
}
複製代碼
就是這麼簡單。 ‘
此組件負責渲染樹中的每一個文件夾。它負責顯示關於當前文件夾的信息,並渲染其子文件夾(若是有的話)。此外,這些文件夾是可單擊的,經過單擊其中一個,組件將顯示其子文件夾和文件。
Template
<template>
<li class="folder" v-bind:class="[folder.leaf ? 'is-leaf' : 'is-folder']">
<span v-on:click="expand()">{{ folder.text }}</span>
<ul class="sub-folders" v-if="folder.children && folder.children.length > 0" v-show="folder.expanded">
<folder v-for="child in folder.children" v-bind:folder="child"></folder>
</ul>
<div class="folder-empty" v-else v-show="!folder.leaf && folder.expanded">No Data</div>
</li>
</template>
複製代碼
Code
export default {
name: "folder",
props: {
folder: Object
},
methods: {
expand() {
if (this.folder.leaf) {
return;
}
this.folder.expanded = !this.folder.expanded;
}
}
};
複製代碼
樣式:
li.is-folder {
padding: 1rem;
border-left: 1px solid #d3d3d3;
margin-bottom: 0.5rem
}
li.is-folder > span {
padding: 0.5rem;
border: 1px solid #d3d3d3;
cursor: pointer;
display:inline-block
}
li.is-leaf {
padding: 0 0 0 1rem;
color: #000;
}
ul.sub-folders {
padding: 1rem 1rem 0 0;
margin: 0;
box-sizing: border-box;
width: 100%;
list-style: none
}
div.folder-empty {
padding: 1rem 1rem 0 1rem;
color: #000;
opacity: 0.5
}
複製代碼
爲了使用我們剛剛建立的組件,所須要作的就是將root
組件導入到須要此功能的地方,並傳遞數據結構。例如,在 App.vue
中使用:
Template
<template>
<div class="vue-app">
<root v-bind:folder="root"></root>
</div>
</template>
複製代碼
Code
import Root from './Root.vue';
export default {
name: 'app',
data: function () {
return {
root: {
text: 'Root Folder',
leaf: false,
expanded: true,
children: [{
text: 'Sub Folder 1',
leaf: false,
expanded: false,
children: [{
text: 'Sub Sub Folder 1',
leaf: false,
expanded: false,
children: [{
text: 'SomeFile1.js',
leaf: true
}]
}, {
text: 'Sub Sub Folder 2',
leaf: false,
expanded: false,
children: []
}, {
text: 'SomeFile.txt',
leaf: true
}]
}]
}
}
},
components: {
Root
}
};
複製代碼
運行效果:
遞歸併不像看起來那麼難,它只是用不一樣的輸入參數一次又一次地執行相同的代碼塊,直到達到結束點。但願本文可以更好幫你們理解遞歸以及如何使用Vue建立遞歸組件。
編輯中可能存在的bug無法實時知道,過後爲了解決這些bug,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug。
乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。
由於篇幅的限制,今天的分享只到這裏。若是你們想了解更多的內容的話,能夠去掃一掃每篇文章最下面的二維碼,而後關注我們的微信公衆號,瞭解更多的資訊和有價值的內容。