需要注意的是include/exclude绑定的属性是页面中设置的name值 而不是路由中的name值
基础使用方法

<keep-alive include="mytemplate">
      <router-view ></router-view>
</keep-alive>
export default {
   name:'mytemplate'
  data(){
      return{}
   }
}

当在实际项目中 可以运用vuex保存你需要缓存的页面的name值,可以配合tabs使用

下面是配合element-ui的tabs使用

二级路由挂载点,由于二级路由页面只有几个基础页面,例如注册登录等,不需要缓存,否则会导致退出登陆后登录页面不更新。建议只在三级路由部署页面缓存。

动态缓存的值存在vuex中,默认将home页面缓存

alive_list: ['/home'], // 缓存得页面

在需要用到的页面,取出缓存页面列表

computed: {
    cacheviews () {
      return this.$store.state.tabs.alive_list
    },
    key () {
      return Date()
    }
  },

一级路由App.vue

<transition name="el-zoom-in-top" mode="out-in">
  <keep-alive :include="cacheviews">
      <!-- 一级路由 -->
      <router-view ></router-view>
  </keep-alive>
</transition>

二级路由

<div class="index-main-content-view-div">
  <transition name="el-zoom-in-top" mode="out-in">
       <!-- 缓存页面 -->
       <keep-alive :include="cacheviews">
            <!-- 二级路由 -->
            <router-view/>
       </keep-alive>
  </transition>
</div>

三级路由挂载点 

<keep-alive :include="cacheviews">
    <!-- 3级路由 -->
    <router-view></router-view>
</keep-alive>

先写vuex文件

const tabs = {
  state: {
    activeName: '/home',
    list: [{
      'name': '工作台',
      'path': '/home'
    }],
    alive_list: ['/home'], // 缓存得页面
    view_key: 1
  },
  mutations: {
    // 切换活动的tag
    changeTabsName (state, data) {
      state.activeName = data
    },
    // 清空所有tag
    emptyTabs (state) {
      state.list = [{
        'name': '工作台',
        'path': '/home'
      }]
      state.activeName = '/home'
    },
    // 添加一个新tage
    changeTabs (state, data) {
      let list = state.list
      let intercept = true
      for (let i = 0; i < list.length; i++) {
        if (list[i].path === data.path) {
          intercept = false
          state.activeName = data.path
          break
        }
      }
      // 如果此页面不在活动列表中,则添加页面缓存
      if (intercept) {
        state.list.push(data)
        // 添加页面缓存列表
        state.alive_list.push(data.path)
        state.activeName = data.path
      }
    },
    // 删除一个tag
    del_tabs (state, data) { // state:变量,data:新值
      let list = state.list // 当前tabs列表
      let alive_list = state.alive_list // 当前缓存列表
      // 如果匹配上path,将该path从tabs列表里删除
      for (let i = 0; i < list.length; i++) {
        if (list[i].path === data.path) {
          list.splice(i, 1)
        }
      }
      state.list = list // 新的tabs列表
      // 如果匹配上path,将该path从alive列表里删除
      for (let i = 0; i < alive_list.length; i++) {
        if (alive_list[i] === data.path) {
          alive_list.splice(i, 1)
        }
      }
      state.alive_list = alive_list // 新的缓存列表
    }
  }
}

export default tabs

每当点击导航栏时,更新vuex

addTab (item) {
      let data = { 'name': item.meta.title, 'path': '/' + item.path }
      this.$store.commit('changeTabs', data)
      this.$storeLocal.set('tabs', this.$store.state.tabs)
    },

当在几个tabs之间来回切换时,不需要更新vuex,直接router跳转就行

当删除tabs时,同样更新vuex

removeTab (targetName) {
      // 获取本地缓存中的tab
      let tabs = this.$storeLocal.get('tabs')
      // let tabs = this.$store.state.list
      for (let i = 0; i < tabs.list.length; i++) {
        let path = tabs.list[i].path
        if (path == targetName) { this.$store.commit('del_tabs', tabs.list[i]) }
      }
      // 回到工作台
      this.$router.push('/')
      // 将新的tab列表存入缓存
      this.$storeLocal.set('tabs', this.$store.state.tabs)
    }

tabs代码:

<template>
<!-- 每点开一个页面会生成一个新的tab -->
  <div class="tabs">
    <!-- 活动窗口 -->
    <el-tabs v-model="$store.state.tabs.activeName" @tab-click="handleClick" @tab-remove="removeTab2" closable>
      <el-tab-pane v-for="item in $store.state.tabs.list" :key="item.name" :label="item.name" :name="item.path"></el-tab-pane>
    </el-tabs>
  </div>
</template>

<script>
export default {
  methods: {
    // 点击tab
    handleClick (tab, event) {
      // console.log(this.$store.state.tabs.alive_list)
      this.$router.push(tab.name)
    },
    // 删掉tab,暂不使用
    removeTab (targetName) {
      // 清空所有vuex中的tab
      this.$store.commit('emptyTabs')
      // 获取本地缓存中的tab
      let tabs = this.$storeLocal.get('tabs')
      // 重新生成vuex的列表,不包含删除的tab
      for (let i = 0; i < tabs.list.length; i++) {
        let path = tabs.list[i].path
        if (path !== targetName) { this.$store.commit('changeTabs', tabs.list[i]) }
      }
      // 回到工作台
      this.$router.push('/home')
      // 将工作台加入tab
      // this.$store.commit('changeTabsName', '/')
      // 将新的tab列表存入缓存
      this.$storeLocal.set('tabs', this.$store.state.tabs)
    },
    removeTab2 (targetName) {
      console.log('删掉tab:' + targetName)
      // 获取本地缓存中的tab
      let tabs = this.$storeLocal.get('tabs')
      // let tabs = this.$store.state.list
      // 遍历storeLocal中存储的tabs列表,如果匹配上,则发起删除方法
      for (let i = 0; i < tabs.list.length; i++) {
        let path = tabs.list[i].path
        if (path == targetName) {
          this.$store.commit('del_tabs', tabs.list[i])
        }
      }
      // 将新的tab列表存入缓存
      this.$storeLocal.set('tabs', this.$store.state.tabs)
      // 跳转至倒数第一个tab
      console.log(this.$store.state.tabs.alive_list)
      let len = this.$store.state.tabs.alive_list.length
      if (len > 0) {
        let to_next_page = this.$store.state.tabs.alive_list[len - 1]
        this.$store.commit('changeTabsName', to_next_page)
        this.$router.push(to_next_page)
      } else {
        // this.$store.state.tabs.view_key++
        this.$store.commit('changeTabsName', '/')
        this.$router.push('/home')
        this.$store.state.tabs.view_key = 2
      }
    }
  },
  created () {
    // 从本地缓存取出活动tabs
    let tabs = this.$storeLocal.get('tabs') ? this.$storeLocal.get('tabs') : ''
    if (tabs === '') {
      return false
    }
    // 仅仅保留最后一个活动tabs
    for (let i = 0; i < tabs.list.length; i++) {
      let name = tabs.list[i].name
      if (name === this.$route.name) {
        this.$store.commit('changeTabs', tabs.list[i])
        this.$store.commit('changeTabsName', tabs.list[i].path)
        this.$storeLocal.set('tabs', this.$store.state.tabs)
        break
      }
    }
  }
}
</script>

<style lang="scss">
@import "./tabs.scss";
</style>

由于keep-alive只能缓存二级路由,这里使用递归处理多余的 layout

新建一个js文件

router.js

// 递归处理多余的 layout : <router-view>,让需要访问的组件保持在第一层 layout 层。
// 因为 `keep-alive` 只能缓存二级路由
// 默认初始化时就执行
function keepAliveSplice (to, router) {
  if (to.matched && to.matched.length > 2) {
    to.matched.map((v, k) => {
      if (v.components.default instanceof Function) {
        // 区分非懒路由
        if (v.components.default.length === 0) {
          v.components.default().then((components) => {
            if (components.default.name === 'parent') {
              to.matched.splice(k, 1)
              router.push({ path: to.path, query: to.query })
              keepAliveSplice(to)
            }
          })
        }
      } else {
        if (v.components.default.name === 'parent') {
          to.matched.splice(k, 1)
          keepAliveSplice(to)
        }
      }
    })
  }
}

export {
  keepAliveSplice
}

在路由router页面里引用

// 路由守卫
router.beforeEach((to, from, next) => {
  keepAliveSplice(to, Router)
  next()
})

结果:

 

Logo

前往低代码交流专区

更多推荐