Vue 解决同一页面缓存切换的问题

666 阅读1分钟

一、使用场景

工作中遇到了一个页面需要根据不同情况决定是否需要缓存。

  1. 主要页面是:主页、列表页、详情页,需要进行缓存切换的是列表页。

  2. 主要操作流程为:主页 -> 列表 -> 详情 -> 列表 -> 主页,其中主页进入列表时需加载最新列表数据,从详情返回列表时则不对列表做修改

二、解决方案

  1. 主要技术:vue + vuex + keep-alive + keep-alive的 include 或者 exclude 属性,此处使用的是 include

  2. 具体方案: 使用 vuex 保存 include 属性值,在进入和离开列表页面之前对 include 做值的修改以切换是否缓存

  3. 代码实现

(1)vuex

const store = new Vuex.Store({
  state: {
    includeArr: [], // keep-alive 需要缓存组件
  },
  getters: {
    getIncludeArr: state => {
      return state.includeArr;
    },
  },
  mutations: {
    /**
     * 修改 keep-alive 的 include 属性值
     * @param state
     * @param payload
     *  - payload.includeArr: string[] ,要修改的组件数组
     *  - payload.isAdd: boolean, 是否为添加
     */
    changeIncludeArr(state, payload){
      let includeArr = payload.includeArr;
      // 此处以字符串数组形式传入,可一次添加或删除多个;
      // 若一次只操作一个也可不加此限制,则下方也做同步修改
      if(Object.prototype.toString.call(includeArr).indexOf('Array')<0){
        return;
      }
      if(includeArr && includeArr.length>0){
        let includeTemp = new Set(state.includeArr);
        if(payload.isAdd){ // 添加
          includeArr.forEach(item => includeTemp.add(item));
        }else{ //删除
          includeArr.forEach(item => includeTemp.delete(item));
        }
        state.includeArr = [...includeTemp];
      }
    },
  },
});

(2)Index.vue

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

export default {
  name: "Index",
  data(){
    return {}
  },
  computed:{
    includeArr: function (){
      return this.$store.getters.getIncludeArr
    },
  },
}
  

(3)List.vue

export default {
  name: "List",
  data() {
    return {}
  },
  beforeRouteEnter(to, from, next){
    // 进入当前页面之前先缓存
    next(vm => {
      vm.$store.commit('changeIncludeArr', {
        isAdd: true,
        includeArr: [vm.$options.name]
      })
    })
  },
  beforeRouteLeave(to, from, next){
    // 离开前判断是否继续缓存此页面
    // 除了前往详情页面,其他都不缓存
    if(to.path.toLowerCase().indexOf('detail') <0){
      this.$store.commit('changeIncludeArr', {
        isAdd: false,
        includeArr: [this.$options.name]
      })
    }
    next();
  },

}