背景:

在公式做ms管理系统。然后老大看事情做差不错了,想要优化一下用户体验。要我在每次用户切换页面后创建一个类似浏览器多页面tag的导航。这样用户在使用时方便做数据比较。

最后长这样

vue3 缓存组件钩子函数_数据

 

分析:

这个放在以前那就是多开一个页面的事儿,让浏览器帮我们保存数据和结构。放到vue里面,因为我们的结构是根据数据决定的,那就是保存一下数据的概念。保存数据的方式瞬间想到sessionstorage、localstorage,但是显然这两个是浏览器级别的,我们是有权限控制的所以pass掉。那就只能放在我们页面的数据里面了。

因为是全局的,你需要在所有页面都可以读取、删除。那就放在vuex这个状态机里面。

然后状态机里面你需要做几件事:

1、添加这个tag(你可能需要判断是否数量会太多,太多的话会影响性能)

2、更新这个tag(更新根据数组的键,就可以了)

3、销毁这个tag

 

数据



export default {
  state: {
    tags: [],//访问过的页面集合
    deepCopy: function(initalObject, finalObject) {
      var finalObject = finalObject || {}
      for (var key in initalObject) {
        var tempProperty = initalObject[key]
        if (tempProperty === initalObject) {
          continue //当自身属性引用自己的时候,跳过执行,不拷贝,避免相互引用导致内存溢出的情况
        }
        if (typeof initalObject[key] === "object" && initalObject[key] !== null) {
          finalObject[key] = (initalObject[key].constructor === Array) ? [] : {} //区分构造函数
          this.deepCopy(initalObject[key], finalObject[key]) //调用自身函数方法
        } else {
          finalObject[key] = initalObject[key]
        }
      }
      return finalObject
    }
  },
  getters: {
    tags(state) {
      return state.tags;
    }
  },
  mutations: {
    //将tag放进tags
    addTags(state, tag) {
      let index = state.tags.length;
      if (index > 8) {
        state.tags.splice(index > 0 ? index - 1 : 0, 1, state.deepCopy(tag));
      } else {
        state.tags.splice(index > 0 ? index : 0, 0, state.deepCopy(tag));
      }

    },
    /*
     *tag.index和state.tags[tag.index]判断key值是否正确以及是否存在数据
     *state.tags[tag.index].name == tag.name 确定修改的路径是否一致,防止删除时修改
     */
    updateTags(state, tag) {
      if (tag.index !== null && state.tags[tag.index] && state.tags[tag.index].name == tag.name) {
        let data = {
          name: state.tags[tag.index].name,
          data: state.deepCopy(tag.data)
        }
        state.tags.splice(tag.index, 1, data);
      }

    },
    delTags(state, index) {
      state.tags.splice(index, 1)
    },
    //从tag进入时,由缓存初始化数据
    cacheDataInit(state, { that, datashow }) {
      let datas = that.$data;
      Object.keys(datas).forEach((val) => {
        that[val] = datashow[val]
      })
    }
  },
  actions: {
    /*
     *在模块复用的时候调用的时候更新数据
     *that 页面this参数
     *to route中的to参数
     */
    beforeRouteUpdate({ commit, state }, { that, to }) {
      let status = that.$route.query.status;

      if (status === 'cache') {
        let index = that.$route.query.key;//该tag在tags数组中的键
        let data = {
          index,
          data: that.$data,
          name: that.$route.path
        }
        commit('updateTags', data);
      }
    },
    /*
     *在路由跳转之前更新数据
     *that 页面this参数
     */
    beforeRouteLeave({ commit, state }, that) {
      if (that.$route.query.status === 'cache') {
        let index = that.$route.query.key;
        let data = {
          index,//所处的键,方便定位到tag
          data: that.$data,//页面数据
          name: that.$route.path//路由名
        }
        commit('updateTags', data)
      } else {
        let data = {
          name: that.$route.path,
          data: that.$data
        }
        commit('addTags', data)
      }
    },
    /*
     *从vuex更新页面的数据
     *that 页面this
     */
    cacheDataInit({ commit, state }, that) {
      let key = that.$route.query.key;
      let datashow = state.tags[key].data;
      commit('cacheDataInit', { that, datashow })
    }
  }
}



 

调用

调用刚开始想在全局直接调用,这样就不用每一个单独去写了啊。然后发现route的全局守卫里面,beforeEach和afterEach这两个内部都没办法使用this。我们内部是一定会调用this来赋值的。所以只能使用组件内守护。beforeRouteEnter(不能读取this排除)、beforeRouteLeave、beforeRouteUpdate。

beforeRouteLeave:在路由离开之前触发。那就可以在这个时候添加我们的tag了。

beforeRouteUpdate:在路由更新时触发。这个时候是不是就可以读取我们的缓存呢??完美



created() {
    let status = this.$route.query.status;//根据status状态来确认是正常的导航还是缓存导航
    if (status === 'cache') {
      this.cacheDataInit(this)
    } else {
      this.getData();//正常获取数据
    }
  },
  beforeRouteLeave(to, from, next) {//离开之前调用添加tag方法
    this.beforeRouteLeave(this)
    next()
  },
  beforeRouteUpdate(to, from, next) {//路由更新时传入进入和离开路由进行判断
    if (!this.$route.query.status && to.query) {
      this.$route.query.key = to.query.key;
      this.cacheDataInit(this)
    } else {
      this.beforeRouteUpdate({ that: this, to })
    }
    next();
  }



tag导航



<div id="scrollNav" v-if='tags.length'>
    <router-link :to="{path:tag.name,query:{status:'cache',key:key}}" v-for='(tag,key) in tags' :key='key' tag="span">
      {{_navName(tag.name)}}/*_navName是根据tag.name返回导航中文的方法*/
      <i class="el-icon-error" @click.stop="delTags(key)"></i>
    </router-link>
  </div>



 

写完能跑起来了,就放心了。。。这都是什么鬼啊