偶然看見别人代碼裡component :is的寫法,一臉懵逼,故查了相關的一些特性,記錄下來,供參考
Vue動态元件 :is
應用場景:在不同元件之間進行動态切換
實作:
<!-- 元件會在 `currentTabComponent` 改變時改變 -->
<component v-bind:is="currentTabComponent"></component>複制代碼
說明:
currentTabComponent
可以包括
- 已注冊元件的名字,或
- 一個元件的選項對象
demo位址:https://github.com/elainema/elaine/tree/master/VUE/vue-components/src/views/sync-components
檢視demo(忽略難看的樣式和布局):
TestComponents.vue:
A.vue
B.vue
當我們切換到A,點選某條文章後,切換至B,再切換回A時,并不會展示選中狀态,操作步驟見圖:
使用<component v-bind:is="currentTabComponent"></component>,切換的時候每次都會觸發生命周期,重新建立動态元件。接下來,我們為元件A和B加上生命周期,并且斷點測試一下:
重新整理頁面,隻觸發了元件A的生命周期
切換至B(為了看起來友善,我先清除了console),觸發了元件B的生命周期
再切換至A(先清除console),再次觸發了元件A的生命周期
可以看到,初始化隻挂載了元件A,每次切換都會重新觸發元件的生命周期,切換時并沒有保留之前的狀态(元件A的選中),但是在在某些情況下,我們更希望那些标簽的元件執行個體能夠被在它們第一次被建立的時候緩存下來。為了解決這個問題,我們可以用一個
<keep-alive>
元素将其動态元件包裹起來。
vue生命周期圖貼一下:
TestComponents.vue,其他代碼不變,隻用
<keep-alive>
元素将 <component :is="currentTabComponent"></component>包裹起來
現在,我們再次重新整理頁面,并且選中一條文章
切換至Tab B,可以看到并沒有銷毀元件A
這時候,我們再次切回至元件A,可以看到,沒有重新觸發元件A的生命周期,并且保留了元件A文章的選中狀态。
深入了解:https://cn.vuejs.org/v2/guide/components-dynamic-async.html
關于keep-alive的詳細api參考:https://cn.vuejs.org/v2/api/#keep-alive
<!-- 失活的元件将會被緩存!-->
<keep-alive>
<component v-bind:is="currentTabComponent"></component></keep-alive>複制代碼
注意這個要求被切換到的元件都有自己的名字,不論是通過元件的
<keep-alive>
選項還是局部/全局注冊。
name
v-show
demo到這裡,我們來說一說為什麼不用
v-show
來切換呢,
V-show
會第一時間加載兩個元件, 兩個元件的生命周期都會觸發,會造成不必要的性能浪費,代碼改一下:
重新整理頁面,可以看到,初始化,元件A和B的生命周期都被觸發了,而在切換時并不會重新觸發元件的生命,會保留元件A的文章選中狀态,如果我們希望切換時重新觸發元件的生命周期,比如重新發送異步請求擷取資料等,則無法實作。
v-if
相信大家都想到了
v-if
,如果是
v-if
的話 确實不會造成同時加載兩個元件,不過
v-if
切換的話, 每次都會重新挂載一次,如果沒有重新渲染的需要的話 ,會造成性能浪費,代碼改一下,看一下效果:
好了,到此 動态元件:is,v-if和v-show的優劣和使用場景大概就這樣了~關于:is的具體使用可以結合官網,搜尋一下網上的例子,就熟悉了~
異步元件
在大型應用中,我們可能需要将應用分割成小一些的代碼塊,并且隻在需要的時候才從伺服器加載一個子產品。為了簡化,Vue 允許你以一個工廠函數的方式定義你的元件,這個工廠函數會異步解析你的元件定義。Vue 隻有在這個元件需要被渲染的時候才會觸發該工廠函數,且會把結果緩存起來供未來重渲染,參考:https://cn.vuejs.org/v2/guide/components-dynamic-async.html#%E5%BC%82%E6%AD%A5%E7%BB%84%E4%BB%B6
1. vue異步元件技術
vue-router配置路由,使用vue的異步元件技術,可以實作按需加載。 但是,這種情況下一個元件生成一個js檔案。 舉例如下:
{
path: '/promisedemo',
name: 'PromiseDemo',
component: resolve => require(['../components/PromiseDemo'], resolve)
}複制代碼
2. es提案的import()
推薦使用這種方式(需要webpack > 2.4)
參考:https://router.vuejs.org/zh/guide/advanced/lazy-loading.html
vue-router配置路由,代碼如下:
// 下面2行代碼,沒有指定webpackChunkName,每個元件打包成一個js檔案。
const ImportFuncDemo1 = () => import('../components/ImportFuncDemo1')
const ImportFuncDemo2 = () => import('../components/ImportFuncDemo2')
// 下面2行代碼,指定了相同的webpackChunkName,會合并打包成一個js檔案。
// const ImportFuncDemo = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/ImportFuncDemo')
// const ImportFuncDemo2 = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/ImportFuncDemo2')
export default new Router({
routes: [
{
path: '/importfuncdemo1',
name: 'ImportFuncDemo1',
component: ImportFuncDemo1
},
{
path: '/importfuncdemo2',
name: 'ImportFuncDemo2',
component: ImportFuncDemo2
}
]
})複制代碼
3. webpack提供的require.ensure()
vue-router配置路由,使用webpack的[require.ensure](Module API - Methods)技術,也可以實作按需加載。 這種情況下,多個路由指定相同的chunkName,會合并打包成一個js檔案。 舉例如下:
{
path: '/promisedemo',
name: 'PromiseDemo',
component: r => require.ensure([], () => r(require('../components/PromiseDemo')), 'demo')
},
{
path: '/hello',
name: 'Hello',
component: r => require.ensure([], () => r(require('../components/Hello')), 'demo')
}複制代碼