前言:
我的需求是后台管理系统,
左侧有menu(切换),上面有tabs(标签,可以切换、关掉、关闭左侧、关闭右侧、关闭其他页面等功能),显示在一块地方(jeecg用的他的模板)
三个方法(两种类型):
1、使用方法,让组件摧毁

this.$destroy()

2、include、extends

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

3、想办法用this.$destroy()更方便的写

说明: 模板开始我用的是

<keep-alive>
    <router-view v-if="keepAlive" />
</keep-alive>
<router-view v-if="!keepAlive" />

根据路由中的keepAlive来看是否需要缓存,本着能不动尽量不动的原则,我采取了第一种方式强制摧毁组件,但暴露出一个问题,就是无论怎么样也缓存不上了,keepAlive也为true,按理说destroy方法应该是摧毁树的节点,但是无论如何也不行,所以采用了第二种include方法:(jeecg有两个地方有缓存的地方this.$destroy应该也可以,先试试)

先说第二种:

jeecg里面有RouteView.vue文件:

 // <keep-alive>
 //   <router-view v-if="keepAlive" />
 // </keep-alive>
 // <router-view v-if="!keepAlive" /> -->
 //改为
 <keep-alive :include="keepAliveList" >
    <router-view />
</keep-alive>
//引入
import { mapState } from 'vuex'
//使用
 computed: {
...mapState({
        keepAliveList: state => state.utils.keepAliveList,
      })
}

TabLayout.vue文件:

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

在methods里:

//mounted里面执行以下,初始数据给到
  stateKeepList(value){
     
      if ( this.linkList.length >1){
        if(value.meta.keepAlive){
         let changKey1 = value.fullPath.split('/')[value.fullPath.split('/').length -1]
         this.$store.dispatch('TOSETPUSH_CHANGEKEEPALIVELIST',changKey1)
        }
      }
      let changKey2 = this.linkList[0].split('/')[this.linkList[0].split('/').length -1]
      this.$store.dispatch('TOSETPUSH_CHANGEKEEPALIVELIST',changKey2)
    },

在watch里面有个监听路由的:

watch: {
    $route: function (newRoute) {
//else if (this.linkList.indexOf(newRoute.fullPath) < 0)   这里面
 if(newRoute.meta.keepAlive){
          let jcNumber = newRoute.name.split('-')[newRoute.name.split('-').length -1]
           this.$store.dispatch('TOSETPUSH_CHANGEKEEPALIVELIST',jcNumber)
        }
}
    }

有关闭左边、关闭右边、关闭其他方法:

//依赖this.linkList所以都要放在方法末尾
  unifiedHandling(){
        let delLeftKeepAlive = [] 
        for(let i =0;i<this.linkList.length;i++){
          let arrOne = this.linkList[i].split('/')[this.linkList[i].split('/').length -1]
          delLeftKeepAlive.push(arrOne)
        }
        this.$store.dispatch('TOSET_CHANGEKEEPALIVELIST',delLeftKeepAlive)
    },

vuex里面:

const uitls = {
    state: {
        screenWidth: 200,
        menuImgCur: true,
    
        keepAliveList: [],
    },
    mutations: {
        SET_SCREENWIDTH:(state, fixed)=>{
            state.screenWidth = fixed
        },
        SET_REDACTMENUIMGCUR:(state,fixed)=>{
            state.menuImgCur =  fixed
        },
    
  
        // 路由信息List方法
        SETPUSH_CHANGEKEEPALIVELIST:(state,fixed)=>{
            state.keepAliveList.push(fixed)
        },
        SET_CHANGEKEEPALIVELIST:(state,fixed)=>{
            state.keepAliveList = [...new Set(fixed)]
            console.log(state.keepAliveList,'组件地址更换')
        }
    },
    actions: {
        // 宽度
        TOSET_SCREENWIDTH({commit},value){
            commit('SET_SCREENWIDTH',value)
        },
        // menu 的菜单模式
        TOSET_REDACTMENUIMGCUR({commit},value){
            commit('SET_REDACTMENUIMGCUR',value)
        },
   
        // 路由信息List方法
        TOSETPUSH_CHANGEKEEPALIVELIST({commit},value){
            commit('SETPUSH_CHANGEKEEPALIVELIST',value)
        },
        TOSET_CHANGEKEEPALIVELIST({commit},value){
            commit('SET_CHANGEKEEPALIVELIST',value)
        },

    }
}
export default uitls

下面就不是很推荐了,也存在很多问题没有去改,还是那个问题,destroy无法再次缓存问题,后面再写

核心:清除cache对象里面的信息,和组件自调用this.$destroy();

一、 路由方法,可以小改

在main.js文件中

Vue.mixin({
  beforeRouteLeave:function(to, from, next){
    console.log('111111111111111触发了')
    console.log(this)
    // 确定是点击关闭按钮过来的   关闭的路由时可缓存的   
    if(from.meta.reload&&from.meta.keepAlive&&this.$vnode.componentOptions) {
      from.meta.reload = false
      var key = this.$vnode.key == null
                  ? this.$vnode.componentOptions.Ctor.cid + (this.$vnode.componentOptions.tag ? `::${this.$vnode.componentOptions.tag}` : '')
                  : this.$vnode.key;
      var cache = this.$vnode.parent.componentInstance.cache;
      var keys  = this.$vnode.parent.componentInstance.keys;
      if (cache[key]) {
        if (keys.length) {
          var index = keys.indexOf(key);
          if (index > -1) {
          keys.splice(index, 1);
          }
        }
        delete cache[key];
      }
      this.$destroy();
    }               
    next();
  },
});
//remove方法中加入这一段
remove(){
  // this.pageList.map( item => {
        //   if(item.fullPath === key ){
        //     console.log(item)
        //     this.$router.push(item.path)
        //     // this.go()
        //     item.meta.reload = true
        //     // this.$route.meta.reload=true
        //   }
        // } )
        }

注意的是需要你在tabs关闭的时候需要打上一个
from.meta.reload = true
方法限制很多,不能在在其他页面关闭,因为要执行这个守卫,并且用这个组件的this.$destryu才能摧毁自己

二、修改成一个方法,脱离路由守卫拦截的实现

 remove(key) {
      console.log(key)
      if (key == indexKey) {
        this.$message.warning('首页不能关闭!')
        return
      }
      if (this.pageList.length === 1) {
        this.$message.warning('这是最后一页,不能再关闭了啦')
        return
      }

      // 找到移除的对象,变成不缓存
      console.log(this.thisParent)
      console.log(this.everyThat)

      let reKet = key
      this.pageList.map((item) => {
        console.log(item.fullPath, reKet)
        if (item.fullPath === reKet) {
          console.log(item)
          let arr = item.fullPath.split('/')
          this.urlName = arr[arr.length - 1]

          for (let i in this.thisParent) {
            console.log(i)
            console.log(this.thisParent[i])
            let arr = this.thisParent[i].tag.split('-')
            this.comName = arr[arr.length - 1]
            console.log(this.comName, this.urlName, false)
            if (this.urlName === this.comName) {
              this.onselectStr = i
              console.log(i)
              // 归零
              // this.urlName = 1
              // this.comName = 2
              console.log(this.urlName, this.comName, true)
              // 进行删除操作
              // var key = this.onselectStr.key == null
              //     ? this.onselectStr.componentOptions.Ctor.cid + (this.onselectStr.componentOptions.tag ? `::${this.onselectStr.componentOptions.tag}` : '')
              //     : this.onselectStr.key;
              console.log(this.everyThat)
              var key = i
              console.log(key, 'key')
              var cache = this.everyThat.$vnode.parent.componentInstance.cache
              console.log(cache, 'cache')
              var keys = this.everyThat.$vnode.parent.componentInstance.keys
              console.log(keys)
              if (cache[key]) {
                if (keys.length) {
                  var index = keys.indexOf(key)
                  if (index > -1) {
                    keys.splice(index, 1)
                  }
                }
                delete cache[key]
                console.log(keys)
              }
              // 循环thatList this的列表,找到那个组件
              // for(let j in this.thatList){
              //   if(j === this.urlName){
              //     j()
              //   }

              // }
              for (let j = 0; j < this.thatList.length; j++) {
                console.log(this.thatList[j])
                let arr = this.thatList[j].$vnode.tag.split('-')
                console.log(arr)
                let str = arr[arr.length - 2]
                console.log(str)
                console.log(this.urlName)
                if (key === str) {
                  console.log('okjinlaile')
                  this.thatList[j].$destroy()
                  return
                }
              }
              // this.everyThat.$destroy();
              console.log('zhixingle  $destroy')
            }
          }
        }
      })

      console.log('this.pageList ', this.pageList)
      this.pageList = this.pageList.filter((item) => item.fullPath !== key)
      let index = this.linkList.indexOf(key)
      this.linkList = this.linkList.filter((item) => item !== key)
      index = index >= this.linkList.length ? this.linkList.length - 1 : index
      this.activePage = this.linkList[index]
      console.log('wei')
    },

每个组件中:

    this.$store.dispatch('TOSET_CHANGETHISPARENT',{cache: this.$vnode.parent.componentInstance.cache,that: this})

vuex中:

state:{
       thisParent: {},
        everyThat: '',
        thatList: [],
},
 mutations: {
   SET_CHANGETHISPARENT:(state,{cache,that})=>{
            state.thisParent = cache
            state.everyThat = that
            
            state.thatList.push(that)
            // let arr = that.$vnode.tag.split('-')
            // let remobj = arr[arr.length -1]
            // state.thatList[`${remobj}`] = that.$destroy()
            console.log(state.thatList)
        }
 },
 actions: {
  // 清缓存
        TOSET_CHANGETHISPARENT({commit},{cache,that}){
            console.log(cache,that)
            commit('SET_CHANGETHISPARENT',{cache,that})
        },
 }

限制也很大:
1、vuex收集太多组件信息(vuex过大)
2、每个组件都需要在mounted里传this
3、组件的name和文件名要一致,否则根据路由信息和name页面匹配,没结果

三、优化思路

TabLayout页面

  clKeepAliveList: [],
 watch: {
    $route: function (newRoute) {
      console.log("新的路由",newRoute)

      //处理缓存list
      let jcNumber = newRoute.name.split('-')[newRoute.name.split('-').length -1]
      console.log(jcNumber)
      if(this.clKeepAliveList.indexOf(jcNumber)<0){
         this.clKeepAliveList.push(jcNumber)
         this.clKeepAliveList =[...new Set(this.clKeepAliveList)] 
         this.$store.dispatch('TOSETPUSH_CHANGEKEEPALIVELIST',jcNumber)
         console.log(this.clKeepAliveList)
      }
}}
mounted(){
this.fn()
},
methods:{
  fn(){
      for(let i= 0;i<this.linkList.length;i++){
         let changKey = this.linkList[i].split('/')[this.linkList[i].split('/').length 					-1]
         this.$store.dispatch('TOSETPUSH_CHANGEKEEPALIVELIST',changKey)
         this.clKeepAliveList.push(changKey)
      }
      console.log(this.clKeepAliveList)
    },
 }

在store的utils:

 keepAliveList: [],
 // 路由信息List方法
    mutations: {
        SETPUSH_CHANGEKEEPALIVELIST:(state,fixed)=>{
            state.keepAliveList.push(fixed)
        },
        SET_CHANGEKEEPALIVELIST:(state,fixed)=>{
            state.keepAliveList = [...new Set(fixed)]
            console.log(state.keepAliveList,'组件地址更换')
        }
       }
  actions: {
  // 路由信息List方法
        TOSETPUSH_CHANGEKEEPALIVELIST({commit},value){
            commit('SETPUSH_CHANGEKEEPALIVELIST',value)
        },
        TOSET_CHANGEKEEPALIVELIST({commit},value){
            commit('SET_CHANGEKEEPALIVELIST',value)
        },
   }

处理的页面:

// 路由缓存管理
import { mapState } from 'vuex'
export default {
    computed: {
        ...mapState({
            keepAliveList: state => state.utils.keepAliveList,
          }),
      
    },
    watch:{
        keepAliveList(e){
            console.log(e)
            // 监听缓存列表的变化,如果缓存列表中没有当前的路由或组件则在缓存中销毁该实例
            let name = this.$options.name;
            console.log(name,'执行到这里了')
            if (e.indexOf(name) < 0) {
                console.log(name,'删除这个组件')
                this.$destroy()
            }
        }
    },
}

其他各个页面:

import DelectComm from  './smallUtils/minxin/delectComm.js'
   mixins: [DelectComm],

现在存在的问题:
1、组件的name和文件名要一致,否则根据路由信息和name页面匹配,没结果
2、因为用的meta的keepalive来做的,所以关闭后出现了一个不能再次缓存的问题

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐