导航
登录 tab 的 demo

include 和 exclude 属性,这两个属性决定哪些组件可以进入缓存。max 属性,通过它可以设置最大缓存数,当缓存的实例超过设置的数时,vue 会移除最久没有使用的组件缓存。activated 组件激活时触发(第一次activated触发是在mounted之后)deactivated组件失活时触发<keep-alive></keep-alive>
在具体实现上,keep-alive 在内部维护了一个 key数组 和一个 缓存对象
//keep-alive 内部声明周期函数
created () {
this.cache = Object.create(null)
this.keys = []
},
max 设置的数值时,keep-alive 会移除 key数组 中的第一个元素 render () {
const slot = this.$slots.default; //获取默认插槽
const vnode = getFirstComponentChild(slot); //得到插槽中第一个组件的vnode
const name = getComponentName(vnode.componentOptions); //获取组件名字
const { cache, keys } = this; //获取当前的缓存内对象和key数组
const key: ?string = vnode.key == null
? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
: vnode.key; //获取组件的key值,如果没有key值,会按照规则自动生成
if (cache[key]) {
//有缓存
//重用组件实例
vnode.componentInstance = cache[key].componentInstance
remove(keys, key); //删除key值
//将key值加入到数组末尾,这样是为了保证最近使用的组件在数组中靠后,主要是为了方便设置的max值删除很久没使用的组件
keys.push(key)
} else {
//没有缓存的则进行缓存
cache[key] = vnode
keys.push(key)
// prune oldest entry
if (this.max && keys.length > parseInt(this.max)) {
//超过最大缓存数量,移除第一个key对应的缓存
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}
vnode.data.keepAlive = true
}
return vnode || (slot && slot[0])
}
来源:https://segmentfault.com/a/1190000040105722
<component :is="DynamicComponent"></component>
const AsyncComponent = () => import('./组件路径');
export default {
components: {
AsyncComponent
}
}
或者:
export default {
components: {
QrcodeLogin: () => import('./QrcodeLogin.vue')
},
}
AsyncComponent = defineAsyncComponent(() =>
new Promise((resolve, reject) => {
resolve({
data() {
return {...}
},
template: ``
});
});
);
或者有大括号:
AsyncComponent = defineAsyncComponent(() => {
return new Promise((resolve, reject) => {
resolve({
data() {
return {...}
},
template: ``
});
});
});
或者:
// npm install Vue 的方式
import { defineAsyncComponent } from 'Vue';
// cdn 引入 Vue 的方式
const { defineAsyncComponent } = Vue;
AsyncComponent = defineAsyncComponent(() => import('./组件路径'));
const AsyncComponent = defineAsyncComponent(() => import('./组件路径'));
export default {
components: {
AsyncComponent
}
}
// or
export default {
components: {
AsyncComponent: defineAsyncComponent(() => import('./组件路径'));
}
}
const AsyncComponent = defineAsyncComponent(() => import('./组件路径'));
app.component('async-comp', AsyncComponent);

MainLogin.vue
<template>
<div class="login-tab">
<div class="login-nav">
<div
v-for="tab of tabData"
:key="tab"
:class="['nav-item', { active: currentTab === tab }]"
@click="changeTab(tab)"
>{{ tab }}</div>
</div>
<div class="login-component">
<keep-alive>
<component :is="currentTabComponent"></component>
</keep-alive>
</div>
</div>
</template>

<template>
<div class="login-tab">
<div class="login-nav">
<div
v-for="tab of tabData"
:key="tab"
:class="['nav-item', { active: currentTab === tab }]"
@click="changeTab(tab)"
>{{ tab }}</div>
</div>
<div class="login-component">
<keep-alive>
<component :is="currentTabComponent"></component>
</keep-alive>
</div>
</div>
</template>
<script>
import AccountLogin from './AccountLogin.vue';
const QrcodeLogin = Vue.defineAsyncComponent(() => import('./QrcodeLogin.vue'));
const MobileLogin = Vue.defineAsyncComponent(() => import('./MobileLogin.vue'));
export default {
name: 'MainLogin',
components: {
AccountLogin,
QrcodeLogin,
MobileLogin,
// vue2用下面形式:
// QrcodeLogin: () => import('./QrcodeLogin.vue')
},
data() {
return {
currentTab: 'Account',
tabData: ['Account', 'Qrcode', 'Mobile'],
}
},
computed: {
currentTabComponent() {
// <account-login></account-login>
return this.currentTab.toLowerCase() + '-login';
}
},
methods: {
changeTab(tab) {
this.currentTab = tab;
}
}
}
</script>
<style lang="scss">
.login-tab {
width: 500px;
margin: 50px auto;
border: 1px solid #000;
.login-nav {
height: 50px;
border-bottom: 1px solid #000;
.nav-item {
float: left;
width: 33.33%;
text-align: center;
line-height: 50px;
&.active {
background-color: #000;
color: #fff;
}
}
}
}
</style>