keep-alive的使用及细节
发表于:2024-04-02 |

前言

脆皮打工人又感冒了,一直咳嗽流鼻涕,真的难搞。所以这几天我也没学习,一直摆烂打打游戏,看看电影啥的,最近遇到个keep-alive的问题,刚好可以顺便重新学习记录下keep-alive的使用。

vue2

首先讲一下vue2中如何使用keep-alive

使用vite创建vue2

bash创建

1
npm init vite

接下来的名称什么的随便搞一个,然后创建类型选择vanilla,而不是vue,因为选择vue创建的是vue3的

安装依赖

首先我们需要安装vite支持vue2的依赖

1
npm install vite-plugin-vue2

然后安装vue,需要带上版本号,你可以先按照我的版本来,但是估计有问题

1
npm install vue@2.7.16

创建修改文件

根目录创建vite.config.js

1
2
3
4
5
6
7
8
// vite.config.js
import { createVuePlugin } from 'vite-plugin-vue2'

export default {
plugins: [
createVuePlugin(/* options */)
],
}

创建src,将main.js放到src目录下

1
2
3
4
5
6
7
8
// main.js
import Vue from "vue";
import App from "./App.vue"

new Vue({
el: "#app",
render: (h) => h(App)
}).$mount();

index.html依赖导入修改

1
<script type="module" src="/src/main.js"></script>

src下创建App.vue,随便写点东西

1
2
3
<template>
<div>Vue 2</div>
</template>

此时npm install将我们vite原先需要的依赖全部安装完成,再npm run dev启动即可
vite初始化vue2项目

编译版本和vue2版本冲突

还记得我说过的你随便安装一个版本可能会报错吗
版本冲突
其实解决方案他也给你了,你只需要将vue版本安装成他的编译版本就可以了
This may cause things to work incorrectly. Make sure to use the same version for both.
我这里的版本是2.7.16,所以我需要执行的是npm install vue@2.7.16

安装并使用路由

这里考点来了,vue2支持的vue-router@3x,别安装最新的即可

配置@

这里为了书写简单点,我在vite.config.ts中进行了@符号的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// vite.config.js
import { createVuePlugin } from 'vite-plugin-vue2'
import path from 'path';

export default {
plugins: [
createVuePlugin(/* options */)
],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
}

配置路由

src下新建一个router文件夹,再新建一个index.js,里面写上这些代码,这里也有个考点,路由的模式,比如history,hash,这有什么区别,

  1. 最明显的区别就是url看上去不太一样,一个有#,一个没有
  2. history发布时候需要进行配置,而hash不用
  3. 还有就是build之后的dist文件夹,如果是history模式,并且服务端此时没有进行相应的配置,live-server打开那个index.html也是空白的
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    import Vue from "vue";
    import Router from "vue-router";
    Vue.use(Router);

    export const constantRoutes = [
    {
    path:"/",
    redirect:"/home"
    },
    {
    path: "/about",
    name: "About",
    component: () => import("@/views/about/index.vue"),
    },
    {
    path: "/home",
    name: "Home",
    component: () => import("@/views/home/index.vue"),
    },
    ];

    export const router = new Router({
    mode: "history", // 需要服务端支持
    scrollBehavior: () => ({ y: 0 }),
    routes: constantRoutes,
    });
    将App.vue进行修改
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <template>
    <div id="app">
    <router-view></router-view>
    </div>
    </template>

    <script>
    export default {
    name: "App",
    };
    </script>
    main.js中进行路由导入
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // main.js
    import Vue from "vue";
    import App from "./App.vue"
    import { router } from "./router/index.js";

    new Vue({
    router,
    el: "#app",
    render: (h) => h(App)
    }).$mount();

然后根据路径去把home和about创建出来即可

为了方便切换路由,加个切换路由的按钮
新建一个layout文件夹,下面新建一个index.vue文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<template>
<div class="layout">
<header class="app-header">
<router-link to="/">首页</router-link>
<router-link to="/about">关于</router-link>
</header>
<section class="app-main">
<transition name="fade-transform" mode="out-in">
<router-view :key="$route.path" />
</transition>
</section>
</div>
</template>
<script>
export default {
name: "Layout",
};
</script>
<style scoped>
.layout{
display: flex;
flex-direction: column;
align-items: center;
}
.app-header{
display: flex;
gap:5px;
}
</style>

将路由进行切换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
export const constantRoutes = [
{
path:"/",
redirect:"/home",
component: () => import("@/layout/index.vue"),
children: [
{
path: "/about",
name: "About",
component: () => import("@/views/about/index.vue"),
},
{
path: "/home",
name: "Home",
component: () => import("@/views/home/index.vue"),
},
]
},
];

然后我将关于页面进行了修改,首页也是类似的修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div class="about">
<div>关于</div>
<input type="text" placeholder="关于" v-model="inputValue">
</div>
</template>
<script>
export default {
name:"About",
data() {
return {
inputValue: "",
};
},
}
</script>

测试keep-alive

无keep-alive效果

ok,到这里,我们先来测试一下,keep-alive生效和没生效的区别吧,此时我们是没有加上keep-alive的

添加keep-alive

通过下面这个视频我们可以看到,当我们切换路由的时候,我们输入的内容并没有保存住,然后我们加上keep-alive

1
2
3
4
5
 <transition name="fade-transform" mode="out-in">
<keep-alive>
<router-view :key="$route.path" />
</keep-alive>
</transition>

我们可以看到,我们输入的内容被保存住了,切换路由回来,内容依旧是在的

keep-alive属性

但是一般我们不可能给所有路由都加上keep-alive,这里就用到了我们keep-alive的俩个属性

  • include
  • exclude
    这俩个属性,分别是对某些缓存,某些不换存,并且要求name值和我们组件暴露的name值要相等,我们一个个实验一下,首先是include
    1
    2
    3
    <keep-alive :include="['Home']">
    <router-view :key="$route.path" />
    </keep-alive>
    此时我们的首页有个name也是Home
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <template>
    <div class="home">
    <div>首页</div>
    <input type="text" placeholder="首页" v-model="inputValue">
    </div>
    </template>
    <script>
    export default {
    name:"Home",
    data() {
    return {
    inputValue: "",
    };
    },
    }
    </script>
    此时的效果如下

同样的,我们实验一下exclude

1
2
3
<keep-alive :exclude="['About']">
<router-view :key="$route.path" />
</keep-alive>

不出所料,实现效果和上面的视频一模一样

vue3

vue3中的keep-alive改造写法

接下来还有一些keep-alive的知识与细节,我们通过vue3来讲解,vue3的项目创建可就太简单了,大家有不会的可以参考我之前的很多文章
我将Home改成了这样,About也是类似的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div class="home">
<div>首页</div>
<input type="text" placeholder="首页" v-model="inputValue">
</div>
</template>
<script>
export default {
name:"Home"
}
</script>
<script setup>
import { ref } from 'vue';
const inputValue = ref('');
</script>

然后将layout也改了,这里我们可以看到vue3中的写法和vue2稍微有点不一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<template>
<div class="layout">
<header class="app-header">
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
</header>
<section class="app-main">
<router-view v-slot="{ Component }">
<transition name="fade">
<keep-alive>
<component :is="Component" :key="$route.path" />
</keep-alive>
</transition>
</router-view>
</section>
</div>
</template>
<script setup>
</script>
<style scoped>
.layout{
display: flex;
flex-direction: column;
align-items: center;
}
.app-header{
display: flex;
gap:5px;
}
</style>

keep-alive中key值的作用

接下来,我们来了解一下为什么要加:key这个属性,其中最主要的原因就是component他的is指向的Component并没有改变,在vue2中的写法,你也可以理解为路由没有改变,你说这是什么情况会发生的呢,我给大家举个例子。
这里我加了一个路由

1
2
3
4
5
 {
path:"user/:id",
name:"User",
component: () => import("@/views/user/index.vue"),
}

然后我把routerLink进行了填充

1
2
3
4
5
6
<header class="app-header">
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<router-link to="/user/1">用户1</router-link>
<router-link to="/user/2">用户2</router-link>
</header>

然后写了一个user的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div class="user">
<div>用户{{ name }}</div>
<input type="text" placeholder="用户" v-model="inputValue">
</div>
</template>
<script setup>
import { ref } from 'vue';
import {useRoute} from 'vue-router';

const inputValue = ref('');
const route = useRoute();

const name=ref("");

if(route.params.id){
name.value=route.params.id;
}
</script>

此时的效果是正常的,内容是有缓存住的

如果我们这个key去掉,就会发生很有趣的事情

这样使用一个组件的内容,keep-alive根本没识别到切换,因此这个key值是非常有必要的

keep-alive生命周期

没错,keep-alive也是有生命周期的,当我们的keep-alive生效的时候
会多出来俩个生命周期activated和deactivated,在vue3中的写法就是onActivated和onDeactivated
我们来测试一下,我将首页代码改成了这样,加上了生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<template>
<div class="home">
<div>首页</div>
<input type="text" placeholder="首页" v-model="inputValue">
</div>
</template>
<script>
export default {
name:"Home"
}
</script>
<script setup>
import { ref ,onActivated,onMounted,onDeactivated} from 'vue';
const inputValue = ref('');

onActivated(()=>{
console.log("home activated");
})

onMounted(()=>{
console.log("home mounted");
})

onDeactivated(()=>{
console.log("home deactivated");
})

</script>

我们可以清晰看到,onMounted只执行了一次,onActivated在每次进入缓存页面时候触发,onDeactivated在每次离开缓存页面的时候触发。

iframe内嵌网页的keep-alive

可以参考我这篇文章的实现,就不多赘述了
https://myblog-5g89ixpbbf1fbfad-1316695488.ap-shanghai.app.tcloudbase.com/2023/06/14/iframe-save-refresh/

我遇到的揪心bug

说到了这还没讲我遇到的bug呢,这个当时也没考虑那么周全,之前我封装了一个业务编辑器组件,他里面的字段真的很多,然后内容也很多,我就拆了很多组件一个个写起来的,为了值方便管理,我把所有的v-model都绑定到了store的值,后续这个组件发包了,就是普通的私有域的npm包,然后在现在要用的时候,结合keep-alive使用就出现了问题,因为需求是多个tag打开同一个这个组件进行编辑,但是因为值都是使用那个组件里面的store,就导致了我的值进行了污染。

结语

本篇文章就先到这里了,更多内容敬请期待,债见~

上一篇:
【Python学习】02-Python爬虫
下一篇:
【JAVA学习】07-跟着黑马程序员课程敲全栈项目(四)