Vue为我们提供了很多高级特性,学习和掌握它们有助于提高你的代码水平。
一、动态组件
动态组件指的是动态切换组件的显示与隐藏。
动态组件实现方式
vue提供了一个内置的组件,专门用来实现动态组件的渲染:通过 is 属性动态指定要渲染的组件。
案例分析
当我们希望页面中的某个地方,在不同组件之间进行动态切换,这时候除了条件渲染,还可以使用动态组件。
<div id="dynamic-component-demo" class="demo">
<button
v-for="tab in tabs"
v-bind:key="tab"
v-bind:class="['tab-button', { active: currentTab === tab }]"
v-on:click="currentTab = tab"
>
{{ tab }}
</button>
<component v-bind:is="currentTabComponent" class="tab"></component>
</div>
<script>
new Vue({
el: "#dynamic-component-demo",
data: {
currentTab: "Home",
tabs: ["Home", "Posts", "Archive"]
},
computed: {
currentTabComponent: function() {
return "tab-" + this.currentTab.toLowerCase();
}
}
});
</script>
在上述示例中,currentTabComponent 可以包括:已注册组件的名字,或一个组件的选项对象。
小Bug
动态组件每一次切换,组件实例都会经历创建和销毁的生命周期。即默认情况下,切换动态组件时无法保持组件的状态。需要借助keep-alive来保持组件状态,以避免反复重新渲染导致的性能问题。
二、缓存组件
动态组件切换后是不会缓存之前被切换掉的组件的,每次切换新组件的时候,Vue 都创建了一个新的组件对象。keep-alive可以缓存动态切换的组件。
实现方式
<!-- 失活的组件将会被缓存!-->
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
注意这个 <keep-alive> 要求被切换到的组件都有自己的名字,不论是通过组件的 name 选项还是局部/全局注册。
对应生命周期
当组件被缓存时,会自动触发组件的 deactivated 生命周期函数。
当组件被激活时,会自动触发组件的 activated 生命周期函数。
常用属性
include 属性用来指定:只有名称匹配的组件会被缓存。多个组件名之间使用英文的逗号分隔。
<keep-alive include="Home,Posts">
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
exclude 只有名称匹配的组件不会被缓存。多个组件名之间使用英文的逗号分隔。
<keep-alive exclude="Home,Posts">
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
三、异步组件
在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。
定义
异步组件就是通过import或者require导入的vue组件。
实现方式
const AsyncComponent = () => ({
// 需要加载的组件 (应该是一个 `Promise` 对象)
component: import('./MyComponent.vue'),
})
优点
进行首屏优化,很大程度的减少性能的消耗,提高用户体验。
四、递归组件
递归组件即:自己内部实现调用自己的组件。
案例分析
实现一个简单的可开关的树状结构界面的 Tree 组件。
<template>
<ul>
<li v-for="(item, index) in data" :key="index" @click.stop="handleClick(item)">
{{item.text}}
<Tree2 v-if="item.expend" :data="item.children"/>
</li>
</ul>
</template>
<script>
export default { //
name: 'Tree2', // 作为内部的标签名
props: ['data'],
methods: {
handleClick (item) {
if (item.hasOwnProperty('expend')) {
item.expend = !item.expend
} else {
this.$set(item, 'expend', true)
}
}
}
}
</script>
注意事项
组件中使用name属性给组件命名才可以调用自己。
递归组件要有结束条件,避免死循环。
使用场景
菜单栏
省市级联动
总结
我们可以根据项目的需求使用恰当的特性进行项目优化。