1. 程式人生 > >【VueJS】VueJS--動態元件 & 非同步元件

【VueJS】VueJS--動態元件 & 非同步元件

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

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

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

PostsArchive

  • Cat Ipsum
  • Hipster Ipsum
  • Cupcake Ipsum

Click on a blog title to the left to view it.

你會注意到,如果你選擇了一篇文章,切換到 Archive

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

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

<!-- 失活的元件將會被快取!-->
<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

來看看修改後的結果:

PostsArchive

Archive component

現在這個 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+ 版本。