偶然看见别人代码里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')
}复制代码