SpringBoot integrates SpringSecurity to implement permission control (9): quickly implement page caching

Series article catalog
"SpringBoot integrates SpringSecurity to achieve permission control (1): Implementation principle"
"SpringBoot integrates SpringSecurity to achieve permission control (2): Basic model design of permission data"
"SpringBoot integrates SpringSecurity to achieve permission control (3): front-end dynamic loading routing and Menu"
"SpringBoot integrates SpringSecurity to achieve permission control (4): role management"
"SpringBoot integrates SpringSecurity to achieve permission control (5): User management"
"SpringBoot integrates SpringSecurity to achieve permission control (6): Menu management"
"SpringBoot integrates SpringSecurity to achieve permissions Control (7): Permission Assignment"
"SpringBoot integrates SpringSecurity to realize permission control (8): realizes multi-tab pages"


1. Problem description

  • In the previous article, we implemented multi-tab pages. These pages are integrated and displayed in the same window in the form of tabs. To switch to a page or close a page, the user only needs to operate the corresponding tab. Very convenient and fast.
    insert image description here
  • However, in the actual use process, we found the following situation: we opened 角色管理the query to find out the role information, opened 用户管理it again, and then switched back again 角色管理, and found that the page was reloaded and refreshed .
    insert image description here

Second, the implementation method of page caching

2.1 keep-alive components

  • We don't want components to be re-rendered to affect the user experience; or for performance considerations, avoid multiple re-rendering and reduce performance. Instead, I hope that the component can be cached to maintain the current state, and the keep-alivecomponent can be used at this time.

When keep-alive wraps dynamic components, inactive component instances are cached instead of destroyed. keep-alive is an abstract component: it does not render a DOM element by itself, nor does it appear in the component's parent component chain.

  • usage:
<keep-alive>
  <component :is="view"></component>
</keep-alive>
  • includeAdded and prop in vue 2.1.0 and later excludeallows components to be cached conditionally. Both can be represented as comma-separated strings, regular expressions, or an array:
    – include - string or regular expression, only matching components will be cached
    – exclude - string or regular expression, any matching components will be cached will not be cached
<keep-alive :include="['a', 'b']">
  <component :is="view"></component>
</keep-alive>

2.1 Use with router-view

The router-view component is a functional component that renders the view component that matches the path. Components rendered by router-view can also embed their own router-view to render nested components according to nested paths.

  • usage:
<transition>
  <keep-alive>
    <router-view></router-view>
  </keep-alive>
</transition>

Third, the specific implementation of page caching

  1. Create a state manager that stores the tab pages opened by the user, which is used to store multiple pages opened by the user and need to be cached
// 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. The tabbar component monitors the routing changes, and when the page corresponding to the routing information is bound to the tabs panel list, we add the page to the Tab state manager
 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. When the user removes the tab page in the Tabbar component, we remove the page from the Tab state manager
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. Modify the main interface component to conditionally cache pages in the state manager
<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>

Fourth, to achieve the effect

insert image description here

5. Source code

Guess you like

Origin blog.csdn.net/jpgzhu/article/details/121372033