【vue學習】動態(tài)組件和異步組件

動態(tài)組件

image

有的時候,在不同組件之間進行動態(tài)切換是非常有用的,比如在一個多標簽的界面里:

image

is

上述內(nèi)容可以通過 Vue<component> 元素加一個特殊的 is 特性來實現(xiàn)

<component v-bind:is="currentTabComponent"></component>

在上述示例中,currentTabComponent 可以包括

  • 已注冊組件的名字,或
  • 一個組件的選項對象
  • component中綁定參數(shù)的方式和普通組件一樣
    image
  • 解析 DOM 模板時的注意事項:有些 HTML 元素,諸如 <ul>、<ol>、<table><select>,對于哪些元素可以出現(xiàn)在其內(nèi)部是有嚴格限制的。而有些元素,諸如 <li>、<tr><option>,只能出現(xiàn)在其它某些特定的元素內(nèi)部。這會導致我們使用這些有約束條件的元素時遇到一些問題。例如:
<table>
  <blog-post-row></blog-post-row>
</table>
  • 這個自定義組件 <blog-post-row> 會被作為無效的內(nèi)容提升到外部,并導致最終渲染結(jié)果出錯。幸好這個特殊的 is 特性給了我們一個變通的辦法:
<table>
  <tr is="blog-post-row"></tr>
</table>

keep-alive

當組件切換時,你有時會想保持這些組件的狀態(tài),以避免反復重渲染導致的性能問題

image

上圖中,你選擇了一篇文章,切換到 Archive 標簽,然后再切換回 Posts,不會繼續(xù)展示之前選擇的文章。因為你每次切換時,Vue 都創(chuàng)建了一個新的 currentTabComponent 實例。

重新創(chuàng)建動態(tài)組件的行為通常非常有用,但該案例中,我們更希望標簽的組件實例能夠被緩存下來。我們可以用 <keep-alive> 元素將其動態(tài)組件包裹起來。

image

image

注意這個 <keep-alive> 要求被切換到的組件都有自己的名字,不論是通過組件的 name 選項還是局部/全局注冊。

組件中的name選項有什么作用?

根據(jù)上面的注意事項,延伸出該問題,下面來看個網(wǎng)上的回答:

vue組件name的作用小結(jié)

  1. 當項目使用keep-alive時,可搭配組件name進行緩存過濾
//假設(shè)我們有個組件命名為detail,
//其中dom加載完畢后我們在鉤子函數(shù)mounted中進行數(shù)據(jù)加載
export default {
  name:'Detail'
},
mounted(){
  this.getInfo();
},
methods:{
  getInfo(){
     axios.get('/xx/detail.json',{
       params:{
        id:this.$route.params.id 
       }
     }).then(this.getInfoSucc)
   }
 }
 /**
 在App.vue中使用了keep-alive導致
 我們第二次進入的時候頁面不會重新請求,
 即不會再次觸發(fā)mounted函數(shù)。

 有兩個解決方案:
 一個增加activated()函數(shù),每次進入新頁面的時候再獲取一次數(shù)據(jù)。
 還有個方案就是在keep-alive中增加一個過濾exclude:
 */
 <div id="app"> 
 <keep-alive exclude="Detail">
  <router-view/>
 </keep-alive>
</div>
  1. DOM做遞歸組件時
<div>
    <div v-for="(item,index) of list" :key="index">
      <div>
        <span class="item-title-icon"></span>
        {{item.title}}
      </div>
      <div v-if="item.children" >
      <!-- detail-list 就是該組件自身 -->
        <detail-list :list="item.children"></detail-list>
      </div>
    </div>
 </div>
<script>
export default {
  name:'DetailList',//遞歸組件是指組件自身調(diào)用自身
  props:{
    list:Array
    /**
    const list = [{
     "title": "A",
     "children": [
     {"title": "A-A","children": [{"title": "A-A-A"}]},
     {"title": "A-B"}]
    }, {
     "title": "B"
    }, {
     "title": "C"
    }, {
     "title": "D"
    }]
    */
  }
}
</script>

迭代結(jié)果如下:


image
  1. 當你用vue-tools時:該調(diào)試工具里顯示的組見名稱是由vue中組件name決定的
    image

異步組件

在大型應(yīng)用中,我們可能需要將應(yīng)用分割成小一些的代碼塊,并且只在需要的時候才從服務(wù)器加載一個模塊。

為了簡化,Vue 允許你以一個工廠函數(shù)的方式定義你的組件,這個工廠函數(shù)會異步解析你的組件定義。

Vue 只有在這個組件需要被渲染時才會觸發(fā)該工廠函數(shù),且會把結(jié)果緩存起來供未來重渲染

知識點

image
  • 如你所見,這個工廠函數(shù)會收到一個 resolve 回調(diào),這個回調(diào)函數(shù)會在你從服務(wù)器得到組件定義的時候被調(diào)用。你也可以調(diào)用 reject(reason) 來表示加載失敗。

  • 這里的 setTimeout 是為了演示用的,如何獲取組件取決于你自己。一個推薦的做法是將異步組件和 webpackcode-splitting 功能一起配合使用:

    image

  • 你也可以在工廠函數(shù)中返回一個 Promise,所以把 webpack 2ES2015 語法加在一起,我們可以寫成這樣:

    image

組件之間的循環(huán)引用

  • 當使用局部注冊的時候,你也可以直接提供一個返回 Promise 的函數(shù):

    image

  • vue處理邊界情況中有一種情況是:組件之間的循環(huán)引用,這里就涉及到了異步加載組件問題:

    image

  • 當你仔細觀察的時候,你會發(fā)現(xiàn)這些組件在渲染樹中互為對方的后代和祖先——一個悖論!
    當通過 Vue.component 全局注冊組件的時候,這個悖論會被自動解開。
    如果你是這樣做的,那么你可以跳過這里。

  • 然而,如果你使用一個模塊系統(tǒng)依賴/導入組件,例如通過 webpackBrowserify,你會遇到一個錯誤:

    image

  • 這里我們可以異步import(具體的我們可以在處理邊界情況一節(jié)中具體再學習

    image

處理加載狀態(tài)

2.3.0+ 新增:這塊的具體應(yīng)用后續(xù)再更新...

這里的異步組件工廠函數(shù)也可以返回一個如下格式的對象:

const AsyncComponent = () => ({
  // 需要加載的組件 (應(yīng)該是一個 `Promise` 對象)
  component: import('./MyComponent.vue'),
  // 異步組件加載時使用的組件
  loading: LoadingComponent,
  // 加載失敗時使用的組件
  error: ErrorComponent,
  // 展示加載時組件的延時時間。默認值是 200 (毫秒)
  delay: 200,
  // 如果提供了超時時間且組件加載也超時了,
  // 則使用加載失敗時使用的組件。默認值是:`Infinity`
  timeout: 3000
})

注意如果你希望在 Vue Router 的路由組件中使用上述語法的話,你必須使用 Vue Router 2.4.0+ 版本。

Vue異步組件處理路由組件加載狀態(tài)的解決方案

  • 在大型單頁面應(yīng)用中,處于對性能的考慮和首屏加載速度的要求,我們一般都會使用webpack的代碼分割和vue-router的路由懶加載功能將我們的代碼分成一個個模塊,并且只在需要的時候才從服務(wù)器加載一個模塊。
  • 但是這種解決方案也有其問題,當網(wǎng)絡(luò)環(huán)境較差時,我們?nèi)ナ状卧L問某個路由模塊,由于加載該模塊的資源需要一定的時間,那么該段時間內(nèi),我們的應(yīng)用就會處于無響應(yīng)的狀態(tài),用戶體驗極差。
  • 【解決方案】這種情況,我們一方面可以縮小路由模塊代碼的體積,靜態(tài)資源使用cdn存儲等方式縮短加載時間,另一方面則可以路由組件上使用異步組件,顯示loadingerror等狀態(tài),使用戶能夠得到清晰明了的操作反饋。
  • 【具體實現(xiàn)】聲明方法,基于Vue動態(tài)組件工廠函數(shù)來返回一個Promise對象
    image

    調(diào)用:
    image
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容