Vue 和遞歸組件

做者:Milos Protic前端

譯者:前端小智vue

來源:vuejsdevelopersgit

你知道的越多,你不知道的越多

github

點贊再看,養成習慣
面試


本文 GitHub:github.com/qq449245884… 上已經收錄,更多往期高贊文章的分類,也整理了不少個人文檔,和教程資料。歡迎Star和完善,你們面試能夠參照考點複習,但願咱們一塊兒有點東西。bash

簡介

有人說遞歸很難理解,也有人不這麼認爲。遞歸函數簡單的定義是:一個自調用函數,這意味着它將在執行的某個時刻調用本身。微信

從理論上講,遞歸是一種須要兩個屬性的行爲:數據結構

  • 結束點:中止遞歸的狀況
  • 一組規則:負責將全部的操做減小到結束點

我們沒法決定哪個更重要。若是沒有結束點,遞歸將成爲一個無限循環,可是若是一組規則就不能實現指望的行爲,因此二者都存在才能使它正常工做。app

遞歸和 Vue 組件

在 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 組件

這個組件是我們文件夾樹的起點。它會開始全部子元素的沉浸,可是若是須要,它也能夠顯示一些獨立的信息,由於它不是遞歸自己的一部分。

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
}
複製代碼

就是這麼簡單。 ‘

folder 組件

此組件負責渲染樹中的每一個文件夾。它負責顯示關於當前文件夾的信息,並渲染其子文件夾(若是有的話)。此外,這些文件夾是可單擊的,經過單擊其中一個,組件將顯示其子文件夾和文件。

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

原文:devinduct.com/blogpost/32…


交流

乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。

github.com/qq449245884…

由於篇幅的限制,今天的分享只到這裏。若是你們想了解更多的內容的話,能夠去掃一掃每篇文章最下面的二維碼,而後關注我們的微信公衆號,瞭解更多的資訊和有價值的內容。

clipboard.png
相關文章
相關標籤/搜索