KeepAlive与RouterView缓存

发布于:2024-12-20 ⋅ 阅读:(12) ⋅ 点赞:(0)

参考

vue动态组件<Component>与<KeepAlive>

KeepAlive官网介绍

缓存之keep-alive的理解和应用

Vue3+Vite KeepAlive页面缓存问题

vue多级菜单(路由)导致缓存(keep-alive)失效

vue3 router-view keeperalive对于同一路径但路径参数不同

效果

在这里插入图片描述

main.js

import { createApp } from 'vue'

import './style.css'

import App from './App.vue'
import router from './router'

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

const app = createApp(App)
app.use(router)
app.use(ElementPlus)
app.mount('#app')

router.js

import { createWebHistory, createRouter } from "vue-router"

import Home from '@/views/Home.vue'
import Chat from '@/views/Chat.vue'
import ChatDetail from '@/views/ChatDetail.vue'

const routes = [
    {
        path: '/',
        redirect: '/home'
    },
    {
        path: '/home',
        name: 'home',
        component: Home
    },
    {
        path: '/chat',
        name: 'chat',
        component: Chat,
        children: [
            {
                path: 'detail/:id',
                name: 'chatDetail',
                component: ChatDetail
            },
        ]
    },
]
const router = createRouter({
    history: createWebHistory(),
    routes,
})

export default router

App.vue

<template>
  <div style="height: 100%;">

    <div class="header">
      <el-button @click="nav('/home')">/home</el-button>
      <el-button @click="nav('/chat')">/chat</el-button>
      <el-button @click="nav('/chat/detail/1')">/chat/detail/1</el-button>
      <el-button @click="nav('/chat/detail/2')">/chat/detail/2</el-button>

      <div style="height:100%;width:1px;background-color:#eee;margin: 10px;"></div>

      <!-- 这里的缓存的意思是: 当从ChatDetail组件切到Home组件时, Chat组件实例里的数据还是否缓存 -->
      <el-button @click="cachedComponents = ['Chat']">缓存chat</el-button>
      <el-button @click="cachedComponents = []">取消缓存chat</el-button>{{cachedComponents}}
    </div>

    <!-- 当在home组件与chat组件切换时, 被切走的组件会被销毁, 切过去的组件会被创建 -->
    <!-- <router-view class="container-wrapper"/> -->

    <!-- home组件和chat组件都仅仅被创建了1次, 当在home组件与chat组件切换时, home组件与chat组件并未被销毁或创建 -->
    <!-- <router-view v-slot="{ Component }">
        <keep-alive>
          <component :is="Component" class="container-wrapper"/>
        </keep-alive>
    </router-view> -->

    <!-- home组件仅被创建了1次并且切走时会被缓存下来不会被销毁, 切过来时不会重新创建; 
         而chat组件被切走会被销毁, 切到chat组件时, chat组件会被创建;
         这里的include指的是 组件名称, 而不是路由名称 -->
    <!-- <router-view v-slot="{ Component }">
        <keep-alive :include="['Home']">
          <component :is="Component" class="container-wrapper"/>
        </keep-alive>
    </router-view> -->

    <router-view v-slot="{ Component }">
        <keep-alive :include="cachedComponents">
          <component :is="Component" class="container-wrapper"/>
        </keep-alive>
    </router-view>

  </div>
</template>

<script setup>
  import {ref} from 'vue'
  import { useRouter, useRoute } from 'vue-router';

  const router = useRouter();
  const route = useRoute();

  const cachedComponents = ref([])

  function nav(path) {
      // console.log(path);
      router.push(path);
  }
</script>

<style>
body,html {
  margin:0;
  padding: 0;
  height: 100%;
}
#app {
  height: 100%;
  & .header {
    height: 51px;
    line-height: 51px;
    padding: 0 20px;
    border-bottom: 1px solid #eee;
    display: flex;
    align-items: center;
    justify-content: flex-start;
  }
  & .container-wrapper {
    height: calc(100% - 52px);
  }
}
</style>

Home.vue

<template>
    <div class="home">
        <div>
            <h1>home</h1>
        </div>
    </div>
</template>

<script setup>
import {ref, onActivated, onDeactivated ,onUnmounted} from 'vue'

    import {useRouter} from 'vue-router';
    // 获取路由器
    const router = useRouter()
    
    console.log('【Home组件】创建');
    
    onUnmounted(()=>{
        console.log('【Home组件】销毁');
    })

</script>

<style lang="scss">
.home {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}
</style>

Chat.vue

<template>
    <div class="container">
        <div class="left">
            <el-button @click="nav('/home')">/home</el-button>
            <el-button @click="nav('/chat/detail/1')">/chat/1</el-button>
            <el-button @click="nav('/chat/detail/2')">/chat/2</el-button>
        </div>
        <div class="right">

            <!-- <router-view/> -->

            <!-- <router-view v-slot="{ Component }">
                <keep-alive>
                    <component :is="Component"/>
                </keep-alive>
            </router-view> -->

            <!-- 这里给component添加1个key之后, 就可以根据路由路径来缓存组件实例了: 1个路由路径对应1个组件实例 -->
            <router-view v-slot="{ Component }">
                <keep-alive>
                    <component :is="Component" :key="route.path"/>
                </keep-alive>
            </router-view>
        </div>
    </div>
</template>

<script setup>
    import { onUnmounted } from 'vue'
    import { useRouter,useRoute } from 'vue-router'
    const route = useRoute()
    const router = useRouter();
    function nav(path) {
        // console.log(path);
        router.push(path);
    }

    console.log('【Chat组件】创建');
    
    onUnmounted(()=>{
        console.log('【Chat组件】销毁');
    })
</script>

<style lang="scss" scoped>
.container {
    display: flex;
    .left {
        width: 220px;
        border-right: 1px solid #eee;
        display: flex;
        flex-direction: column;
        align-items: center;
        padding-top: 10px;
        background-color: #f2f2f2;
        .el-button {
            margin-bottom: 10px;
            width: 80%;
        }
    }
    .right {
        flex: 1;
        padding: 20px;
        background-color: #e1e1e1;
    }   
}
.el-button+.el-button {
    margin-left: 0;
}
</style>
ChatDetail.vue
<template>
    <div class="chat-box">
        <div class="header">
            <h1>会话{{route.params.id}}</h1>
        </div>
        <div class="msg-list">
            <el-input v-model="content" placeholder="请输入"></el-input>
        </div>
    </div>
</template>

<script setup>
import {ref, onActivated, onDeactivated ,onUnmounted} from 'vue'
import {useRoute} from 'vue-router';
const content = ref();
const route = useRoute();

onActivated(()=>{
    console.log('---【ChatDetail组件】激活---');
});
onDeactivated(()=>{
    console.log('---【ChatDetail组件】取消激活---');
});

console.log('---【ChatDetail组件】创建---');

onUnmounted(()=>{
    console.log('---【ChatDetail组件】销毁---');
})

</script>

<style lang="scss" scoped>
    .chat-box {
        display: flex;
        flex-direction: column;
        height: 100%;
        .msg-list {
            flex: 1;
        }
    }
    .header {
        border: 2px solid #eee;
        line-height: 68px;
        height: 68px;
        h1 {
            margin: 0;
        }
    }
</style>