首先,做这个目的是产品多次提出页面缓存的问题,导致客户抱怨,一直没有解决,那能怎么办,只能我上了

网上找了很多方案,发现通过条件控制include的值是最好的方案,而不是之前的判断meta里面的值

使用include的方案也差不多是通过传参去判断,但是不怎么优雅,相对于新项目可以这样,但是老项目就是大改造

 

本项目是基于左侧菜单选择,然后右侧展示内容去设计

实现方案

  1.路由配置,获取路由列表

  2.监听路由变化,获取当前页面的路由名称进行保存或销毁

  3.页面name属性声明,声明即缓存

 

1.路由配置

  1.首先配置路由列表

import Router from "vue-router";
import Vue from "vue";
import layout from '@/views/layout/layout'

Vue.use(Router);
const routersList = [
    {
        path: '/',
        component: (resolve) => require(["@/views/layout/index"], resolve),
        children: [{
            path: 'A',
            component: layout,
            children: [
                {
                    path: '',
                    name: 'A1',  //标注了name的页面为待缓存列表
                    component: () => import('@/views/layout/test1.vue'),
                },
                {
                    path: 'A1_child', //A1_child的子列表为内部跳转页面,也可抽出跟A1同级(路径名称随意)
                    component: layout,
                    children: [
                        {
                            path: 'A2',
                            name: 'A2',
                            component: () => import('@/views/layout/test2.vue'),
                        },
                        {
                            path: 'A2_child',
                            component: layout,
                            children: [{
                                path: 'A3',
                                name: 'A3',
                                component: () => import('@/views/layout/test3.vue'),
                            },]
                        },
                    ]
                },
            ]
        },{
            path: 'B',
            component: layout,
            children: [
                {
                    path: '',
                    name: 'B1',
                    component: () => import('@/views/layout/test4.vue'),
                },
                {
                    path: 'B1_child',
                    component: layout,
                    children: [
                        {
                            path: 'B2',
                            name: 'B2',
                            component: () => import('@/views/layout/test5.vue'),
                        },
                        {
                            path: 'B2_A2',
                            name: 'B2_A2',
                            component: () => import('@/views/layout/test2.vue'),
                        },
                    ]
                },
            ]
        }]
    }
];
export {routersList}

以上是配置的两套路由

  1.A1->A2->A3  A1跳转A2跳转A3  

     A3->A2->A1  A3返回,A2缓存;A2返回,A1缓存

  2.B1->B2->B2_A2  B1跳转B2跳转B2_A2

     B2_A2->B2->B1  B2_A2返回,B2缓存;B2返回,B1缓存

  这样很清楚知道缓存的东西(原谅我不会画图)

  定义

    name:标注了name的页面为待缓存列表,只有这些页面才会被缓存

    A1_child:列表为内部跳转页面,相当于子列表,也可抽出跟A1同级

 

 

  2.layout组件,用于每层页面缓存

<template>
    <keep-alive :include="include">
        <router-view></router-view>
    </keep-alive>
</template>

<script>
    export default {
        computed:{
            include(){
                return this.$store.state.include
            },
        },
    }
</script>

2.监听路由变化,获取当前页面的路由名称进行保存或销毁

  App.vue页面

<template>
  <div id="app">
    <keep-alive :include="include">
      <router-view></router-view>
    </keep-alive>
  </div>
</template>

<script>
  import CacheClass from '@/assets/js/config/CacheClass'
  export default {
    computed:{
      include(){
        return this.$store.state.include
      },
    },
    watch: {
      $route(to,from) {
        console.log('路由变化',this.$route)
        this.cache.queryModule(to,from)
      },
    },
    mounted() {this.cache=new CacheClass({instance:this})
    }
  }
</script>
CacheClass.js
import {routersList} from '@/router'
class CacheClass {
    constructor(params={}) {
        this.routersList=routersList //路由列表
        this.instance=params.instance  //vue实例
        this.cacheList=[] //模块缓存列表
        this.includeList=[]
        this.init()
    }
    init(){
        this.getCacheList()
    }
    getCacheList(){
        const fn=(list,obj)=>{
            for(let i in list){
                if(list[i].children&&list[i].children.length){
                    fn(list[i].children,obj)
                }else{
                    if(list[i].name){
                        if(!obj.module) obj.module=list[i].name
                        obj.children.push(list[i].name)
                    }
                }
            }
        }
        const tmp=[]
        for(let i in this.routersList){
            tmp.push({
                module:'',
                children:[]
            })
            fn(this.routersList[i].children,tmp[tmp.length-1])
        }
        this.cacheList=tmp
    }
    queryModule(to,from){
        if(!to.name) return
        // console.log(to,from)
        // console.log(this.cacheModule,'当前模块')
        let cacheList=this.cacheList
        //查出当前路由所在的列表
        let cacheName=''
        let list=[],otherList=[] //其他列表
        cacheList.map(item=>{
            if(item.module!==this.cacheModule) {
                otherList.push(item)
            }else{
                list=list.concat(item.children)
            }
        })
        // console.log('不存在列表',otherList)
        // console.log('列表',list)
        const reset=()=>{
            otherList.map(item=>{
                if(item.children.includes(to.name)){
                    cacheName=item.module
                }
            })
            this.cacheModule=cacheName
            if(cacheName){
                console.log('设置模块')
                this.includeList=[to.name]
                this.setInclude()
            }else{
                console.log('清空模块')
                this.includeList=[]
                this.setInclude()
            }
        }
        this.includeList=JSON.parse(JSON.stringify(this.instance.$store.state.include)) //获取缓存列表
        if(list.length) {
            if(list.includes(to.name)){
                console.log('包含模块')
                if(!this.includeList.includes(to.name)){  //第一次会记录模块(页面都加进去,只要组件不加name就不生效)
                    console.log('添加',to.name)
                    this.includeList.push(to.name)
                    this.setInclude()
                }else if(this.includeList.includes(from.name)){ //模块返回检查清空
                    console.log('移除',from.name)
                    const index=this.includeList.findIndex(item=>item===from.name)
                    if(index>-1) {
                        this.includeList.splice(index,1)
                        this.setInclude()
                    }
                }
            }else{
                console.log('不包含模块,其他模块查找1')
                reset()
            }
        }else{
            console.log('不包含模块,其他模块查找2')
            reset()
        }
        console.log('当前路由值',this.includeList)
    }
    setInclude(){
        this.instance.$store.commit('setInclude',this.includeList)
    }
}

export default CacheClass

 

 setInclude(state, e){
    state.include=e
  }

 

3.页面name属性声明,声明即缓存

name:'A1'

 

 include缓存是通过页面name去缓存的,所以声明后就相当于缓存,值与路由定义的name保持一致

 

 

PS

  1.不管跳转的页面要不要缓存,都需要填写name,加入待缓存列表

  2.B2页面要跳到B2_A2(即A2页面),那么B2_A2必须加入到B1_child的子列表,否则不生效

   所以路由跳转以name的形式跳转 this.$router.push({name:'B2_A2'})

  3.一种情况就是共用A2页面,都需要进行缓存,页面name怎么设值,可以通过组件形式引入,再分别设置name