SpringBoot整合SpringSecurity实现权限控制(九):快速实现页面缓存

系列文章目录
《SpringBoot整合SpringSecurity实现权限控制(一):实现原理》
《SpringBoot整合SpringSecurity实现权限控制(二):权限数据基本模型设计》
《SpringBoot整合SpringSecurity实现权限控制(三):前端动态装载路由与菜单》
《SpringBoot整合SpringSecurity实现权限控制(四):角色管理》
《SpringBoot整合SpringSecurity实现权限控制(五):用户管理》
《SpringBoot整合SpringSecurity实现权限控制(六):菜单管理》
《SpringBoot整合SpringSecurity实现权限控制(七):权限分配》
《SpringBoot整合SpringSecurity实现权限控制(八):实现多标签页》


一、问题描述

  • 在上篇文章中,我们实现了多标签页,这些页面以标签的形式集成在同一个窗口显示,要想切换到某个页面或是关闭某个页面,用户只需要操作相应的标签即可,非常方便快捷。
    在这里插入图片描述
  • 但实际使用过程中,却发现以下情况:我们打开角色管理查询出角色信息,又打开了用户管理,之后再次切换回角色管理发现这个页面被重新加载刷新了
    在这里插入图片描述

二、页面缓存的实现方法

2.1 keep-alive组件

  • 我们不希望组件被重新渲染影响用户体验;或者处于性能考虑,避免多次重复渲染降低性能。而是希望组件可以缓存下来,维持当前的状态,这时候就可以用到keep-alive组件。

keep-alive 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。keep-alive 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。

  • 用法:
<keep-alive>
  <component :is="view"></component>
</keep-alive>
  • 在vue 2.1.0后的版本中新增includeexclude prop 允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示:
    – include - 字符串或正则表达,只有匹配的组件会被缓存
    – exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存
<keep-alive :include="['a', 'b']">
  <component :is="view"></component>
</keep-alive>

2.1 配合router-view使用

router-view 组件是一个 functional 组件,渲染路径匹配到的视图组件。router-view渲染的组件还可以内嵌自己的 router-view,根据嵌套路径,渲染嵌套组件。

  • 用法:
<transition>
  <keep-alive>
    <router-view></router-view>
  </keep-alive>
</transition>

三、页面缓存的具体实现

  1. 创建一个存储用户打开的Tab页面的状态管理器,用来存放用户打开的且需要缓存的多个页面
// src/store/modules/tabbar.js
const state = {
    
    
  cachedViews: []
}

const mutations = {
    
    
  // 添加缓存页面
  ADD_CACHED_VIEW: (state, view) => {
    
    
    if (state.cachedViews.includes(view.name)) return
    if (!view.meta.noCache) {
    
    
      state.cachedViews.push(view.name)
    }
  },
  // 删除缓存页面
  DEL_CACHED_VIEW: (state, view) => {
    
    
    for (const i of state.cachedViews) {
    
    
      if (i === view.name) {
    
    
        const index = state.cachedViews.indexOf(i)
        state.cachedViews.splice(index, 1)
        break
      }
    }
  },
  // 删除全部缓存页面
  DEL_ALL_CACHED_VIEWS: state => {
    
    
    state.cachedViews = []
  }

}

const actions = {
    
    

  addCachedView({
     
      commit }, view) {
    
    
    commit('ADD_CACHED_VIEW', view)
  },

  delCachedView({
     
      commit, state }, view) {
    
    
    return new Promise(resolve => {
    
    
      commit('DEL_CACHED_VIEW', view)
      resolve([...state.cachedViews])
    })
  },

  delAllCachedViews({
     
      commit, state }) {
    
    
    return new Promise(resolve => {
    
    
      commit('DEL_ALL_CACHED_VIEWS')
      resolve([...state.cachedViews])
    })
  }

}

export default {
    
    
  namespaced: true,
  state,
  mutations,
  actions
}

  1. Tabbar组件中监控路由变化情况,将路由信息对应的页面与tabs panel列表进行绑定时,我们把该页面加入Tab状态管理器
 watch: {
    
    
    $route: {
    
    
      handler(to, form = null) {
    
    
        // 当路由改变时,检测该路由是否已经在打开的页面之中,如果不在,就添加进去
        if (to.meta) {
    
    
          this.pageCurrent = to.path
          var index = this.pageList.findIndex(value => {
    
    
            return value.name === to.path
          })
          if (index < 0) {
    
    
            this.pageList.push({
    
     name: to.path, label: to.meta.title, icon: to.meta.icon })
          }
          // 将需要缓存的页面放入状态管理器
          const {
    
     name, meta } = this.$route
          if (name && meta !== undefined && meta.noCache !== undefined && !meta.noCache) {
    
    
            this.$store.dispatch('tabbar/addCachedView', this.$route)
          }
        }
      },
      immediate: true
    }
  }
  1. Tabbar组件中用户移除tab页时,我们把该页面从Tab状态管理器中移除
removeTab(targetName) {
    
    
      if (targetName === '/dashboard') return
      const tabs = this.pageList
      let activeName = this.pageCurrent
      if (activeName === targetName) {
    
    
        tabs.forEach((tab, index) => {
    
    
          if (tab.name === targetName) {
    
    
            const nextTab = tabs[index + 1] || tabs[index - 1]
            if (nextTab) {
    
    
              activeName = nextTab.name
            }
          }
        })
      }
      this.pageCurrent = activeName

      this.pageList = tabs.filter(tab => tab.name !== targetName)
      // 将需要缓存页面从状态管理器中移除
      this.$store.dispatch('tabbar/delCachedView', this.$route)
      this.$router.push({
    
     path: activeName })
    }
  1. 修改主界面组件,实现有条件地对状态管理器中的页面进行缓存
<template>
  <section class="app-main">
    <!-- 有条件地对状态管理器的页面进行缓存v-->
    <transition name="fade-transform" mode="out-in">
      <keep-alive :include="this.$store.state.tabbar.cachedViews">
        <router-view :key="key" />
      </keep-alive>
    </transition>
  </section>
</template>

<script>
export default {
      
      
  name: 'AppMain',
  computed: {
      
      
    // 页面缓存状态管理器
    cachedViews() {
      
      
      return this.$store.state.tabbar.cachedViews
    },
    key() {
      
      
      return this.$route.path
    }
  }
}
</script>

<style scoped>
.app-main {
      
      
  /*50 = navbar  */
  min-height: calc(100vh - 50px);
  width: 100%;
  position: relative;
  overflow: hidden;
}
.fixed-header+.app-main {
      
      
  padding-top: 50px;
}
</style>

<style lang="scss">
// fix css style bug in open el-dialog
.el-popup-parent--hidden {
      
      
  .fixed-header {
      
      
    padding-right: 15px;
  }
}
</style>

四、实现效果

在这里插入图片描述

五、源码

猜你喜欢

转载自blog.csdn.net/jpgzhu/article/details/121372033
今日推荐