Vue3 uses keep-alive components, including dynamic components
This article directory
Components do not use keep-alive
- Father
<template>
<div>
Father
<el-button @click="tabChange">change page</el-button>
<Child :msg="cutTab" v-if="cutTab"></Child>
<Child2 :msg="cutTab" v-else></Child2>
</div>
</template>
<script setup lang="ts" name="Father">
const cutTab = ref(false);
const tabChange = () => {
cutTab.value = !cutTab.value;
}
</script>
- Child
<template>
<div class="c1">
Child +
{
{ props.msg }}
<el-input v-model="input" placeholder="Please input" />
</div>
</template>
<script setup lang="ts" name="Child">
const props = defineProps({
msg: {
type: Boolean,
default: false,
},
})
const input = ref('')
</script>
- Child2
<template>
<div class="c2">
Child2 +
{
{ props.msg }}
<el-input v-model="input" placeholder="Please input" />
</div>
</template>
<script setup lang="ts" name="Child2">
const props = defineProps({
msg: {
type: Boolean,
default: false,
},
})
const input = ref('')
</script>
![](https://img-blog.csdnimg.cn/a2207c2b71ec4fa7bee76e33e91c7360.jpeg)
![](https://img-blog.csdnimg.cn/683bfa7676804f32a753c886e51d8187.jpeg)
used in the component
- include: include
- exclude: exclude
v-if switch
<keep-alive>
<Child :msg="cutTab" v-if="cutTab"></Child>
<Child2 :msg="cutTab" v-else></Child2>
</keep-alive>
<keep-alive include="Child2">
<Child :msg="cutTab" v-if="cutTab"></Child>
<Child2 :msg="cutTab" v-else></Child2>
</keep-alive>
![](https://img-blog.csdnimg.cn/8735629074704562bbf7bad12b44df21.jpeg)
![](https://img-blog.csdnimg.cn/6a80fbefcc4f430ca0a3f95ec8002d9d.jpeg)
![](https://img-blog.csdnimg.cn/f8355821219c4ab2a4a68042fa4b013f.gif)
component dynamic component switching
Unexpected error due to annotation
<KeepAlive> expects exactly one child component
<keep-alive include="Child2">
<!-- <Child :msg="cutTab" v-if="cutTab"></Child>
<Child2 :msg="cutTab" v-else></Child2> -->
<component :is="com"></component>
</keep-alive>
keep-alive
Do not use comments in components, they will be parsed as child nodes
- Add div to wrap
<keep-alive include="Child2">
<div>
<!-- <Child :msg="cutTab" v-if="cutTab"></Child>
<Child2 :msg="cutTab" v-else></Child2> -->
<component :is="com"></component>s
</div>
</keep-alive>
- remove comment
<keep-alive include="Child2">
<component :is="com"></component>
</keep-alive>
Use of dynamic components
[Vue warn]: Vue received a Component which was made a reactive object. This can lead to unnecessary performance overhead, and should be avoided by marking the component with 'markRaw' or using 'shallowRef' instead of 'ref'.
![](https://img-blog.csdnimg.cn/37dbe7974c6d43f6b0561c0e5f919556.jpeg)
In Vue 3, if you use ref or reactive to wrap a component into a reactive object, it may cause unnecessary performance overhead. Because this will make Vue try to track component changes, but the component instance does not actually need to be tracked. A component itself should not be reactive, only its props and state should be reactive.
Therefore, when you need to refer to a component, you should use shallowRef
or markRaw
, which can avoid making the entire component responsive, and only track changes in the reference
- Use markRaw
const com = ref(markRaw(Child2));
const comChange = () => {
if(com.value === Child2){
com.value = markRaw(Child);
}else{
com.value = markRaw(Child2);
}
}
- Use shallowRef
const com = shallowRef(Child2);
const comChange = () => {
if(com.value === Child2){
com.value = Child;
}else{
com.value = Child2;
}
}
complete example
<template>
<div>
Father
<el-button @click="comChange">change component</el-button>
<keep-alive include="Child2">
<component :is="com"></component>
</keep-alive>
</div>
</template>
<script setup lang="ts" name="Father">
import Child from "@/views/Child.vue";
import Child2 from "@/views/Child2.vue";
const cutTab = ref(false);
const com = ref(markRaw(Child2));
const comChange = () => {
if(com.value === Child2){
com.value = markRaw(Child);
}else{
com.value = markRaw(Child2);
}
}
</script>
It can be seen that only Child2
components are cached, Child
destroyed and generated
Routing does not use keep-alive
- components
<template>
<div>
Father
<div class="nav">
<router-link to="/Father/Child">去Child页面</router-link>
<el-divider direction="vertical" />
<router-link to="/Father/Child2">去Child2页面</router-link>
</div>
<router-view></router-view>
</div>
</template>
- route-index.ts
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
const routes = [
{
path: '/Father',
name: 'Father',
component: () => import('@/views/Father.vue'),
children: [
{
path: 'Child',
name: 'Child',
component: () => import('@/views/Child.vue'),
},
{
path: 'Child2',
name: 'Child2',
component: () => import('@/views/Child2.vue'),
}
],
},
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
![](https://img-blog.csdnimg.cn/b1849e7c508944bc8eba79988900a903.gif)
used in routing
-
Vue Router 4
(the routing library that comes with Vue 3) introduces a new API for routing-level routing<keep-alive>
. This is the API<router-view>
of the componentv-slot
- It should be noted that
v-if
do not add tokeep-alive
it, it will be destroyed directlykeep-alive
, it needs to be addedcomponent
to - To achieve partial refresh of the page, the life cycle executed when the page enters is:
created->mounted->activated
- It should be noted that
<template>
<div>
Father
<div class="nav">
<router-link to="/Father/Child">去Child页面</router-link>
<el-divider direction="vertical" />
<router-link to="/Father/Child2">去Child2页面</router-link>
</div>
<router-view v-slot="{ Component }">
<keep-alive >
<component :is="Component" v-if="$route.meta.keepAlive"/>
</keep-alive>
<component :is="Component" v-if="!$route.meta.keepAlive"/>
</router-view>
</div>
</template>
-
route-index.ts
- Add an attribute to the corresponding route
meta
to set whether the page should use the cache
- Add an attribute to the corresponding route
...
const routes = [
{
path: '/Father',
name: 'Father',
component: () => import('@/views/Father.vue'),
children: [
{
path: 'Child',
name: 'Child',
component: () => import('@/views/Child.vue'),
},
{
path: 'Child2',
name: 'Child2',
meta: {
keepAlive: true, // 需要被keep-alive
},
component: () => import('@/views/Child2.vue'),
}
],
},
]
...
![](https://img-blog.csdnimg.cn/0c5a0875bd1f4f0aad7ffbc4caf443c7.gif)
keep-alive life cycle
Some keep-alive
components will have two more life cycles, after mounted
and unMounted
before
onActivated(() => {
console.log('Component is activated')
})
onDeactivated(() => {
console.log('Component is deactivated')
})
![](https://img-blog.csdnimg.cn/8a6e4826d8934c3eac8a1f127c289ee8.jpeg)
![](https://img-blog.csdnimg.cn/09bcfa2d7c6e4552b52b3393b88bb71c.gif)