動態組件 & 非同步組件


該頁面假設你已經閱讀過了元件基礎。如果你還對組件不太了解,推薦你先閱讀它。


目錄


在動態元件上使用keep-alive


我們之前曾經在一個多標籤的介面中使用is 特性來切換不同的元件:

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

當在這些元件之間切換的時候,你有時會想保持這些元件的狀態,以避免反覆重渲染導致的效能問題。例如我們來展開說一說這個多標籤介面:

1.gif

你會注意到,如果你選擇了一篇文章,切換到Archive 標籤,然後再切換回Posts,是不會繼續展示你之前選擇的文章的。這是因為你每次切換新標籤的時候,Vue 都建立了一個新的 currentTabComponent 實例。

重新建立動態元件的行為通常是非常有用的,但是在這個案例中,我們更希望那些標籤的元件實例能夠被在它們第一次被創建的時候快取下來。為了解決這個問題,我們可以用一個 <keep-alive> 元素將其動態元件包裹起來。

<!-- 失活的组件将会被缓存!-->
<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

來看看修改後的結果:

2.gif

現在這個Posts 標籤保持了它的狀態(被選中的文章) 甚至當它未被渲染時也是如此。你可以在這個 fiddle 查閱到完整的程式碼。

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

你可以在 API 參考文件 查閱更多關於 <keep-alive> 的細節。


非同步元件


在大型應用程式中,我們可能需要將應用程式分割成小一些的程式碼區塊,並且只在需要的時候才從伺服器載入一個模組。為了簡化,Vue 允許你以一個工廠函數的方式定義你的元件,這個工廠函數會非同步解析你的元件定義。 Vue 只有在這個元件需要被渲染的時候才會觸發該工廠函數,並且會把結果緩存起來供未來重渲染。例如:

Vue.component('async-example', function (resolve, reject) {
  setTimeout(function () {
    // 向 `resolve` 回调传递组件定义
    resolve({
      template: '<div>I am async!</div>'
    })
  }, 1000)
})

如你所見,這個工廠函數會收到一個 resolve 回調,這個回呼函數會在你從伺服器得到元件定義的時候被呼叫。你也可以呼叫 reject(reason) 來表示載入失敗。這裡的 setTimeout 是為了示範用的,如何取得元件取決於你自己。一個建議的做法是將非同步元件和webpack 的code-splitting 功能一起配合使用:

Vue.component('async-webpack-example', function (resolve) {
  // 这个特殊的 `require` 语法将会告诉 webpack
  // 自动将你的构建代码切割成多个包,这些包
  // 会通过 Ajax 请求加载
  require(['./my-async-component'], resolve)
})

你也可以在工廠函數中傳回一個Promise,所以把webpack 2 和ES2015 語法加在一起,我們可以寫成這樣:

Vue.component(
  'async-webpack-example',
  // 这个 `import` 函数会返回一个 `Promise` 对象。
  () => import('./my-async-component')
)

當使用局部註冊的時候,你也可以直接提供一個返回Promise 的函數:

new Vue({
  // ...
  components: {
    'my-component': () => import('./my-async-component')
  }
})

如果你是一個 Browserify 用戶同時喜歡使用非同步元件,很不幸這個工具的作者明確表示異步載入「並不會由 Browserify 支持”,至少官方不會。 Browserify 社群已經找到了一些變通方案,這些方案可能對已存在的複雜應用有幫助。對於其它的場景,我們推薦直接使用 webpack,以擁有內建的頭等非同步支援。


#處理載入狀態

#2.3.0  新增

這裡的非同步元件工廠函數也可以傳回一個如下格式的物件:

const AsyncComponent = () => ({
  // 需要加载的组件 (应该是一个 `Promise` 对象)
  component: import('./MyComponent.vue'),
  // 异步组件加载时使用的组件
  loading: LoadingComponent,
  // 加载失败时使用的组件
  error: ErrorComponent,
  // 展示加载时组件的延时时间。默认值是 200 (毫秒)
  delay: 200,
  // 如果提供了超时时间且组件加载也超时了,
  // 则使用加载失败时使用的组件。默认值是:`Infinity`
  timeout: 3000
})

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