页签/tab页数据缓存方案

概述:
使用单独Vue实例保存子应用实例 子应用查询表单数据 子应该表格数据
父级应用:
1. 父级应用中创建VueEmit.js文件中 new Vue() 用于存放子应用实例 

basic应用 
vueEmit.js

import Vue from 'vue'
var VueEvent = new Vue()
VueEvent.loadedApplicationMap = {} // 子应用缓存
VueEvent.isAddTab = false // 记录tab页签的变化前的值
export default VueEvent

2.父级应用中提供卸载子应用并缓存子应用的方法unmountCache 

 utils.js

// 父应用提供unmountCache方法
export function unmountCache(cacheKey, instance) {
  // 此处永远只会保存首次加载生成的实例
  let cachedInstance = {}
  cachedInstance = instance
  // keepalive设置为必须 防止进入时再次created,同keep-alive实现
  if (!cachedInstance._vnode.data.keepAlive) cachedInstance._vnode.data.keepAlive = true
  // loadedApplicationMap用于是key-value形式,用于保存当前应用的实例
  vueEvent.loadedApplicationMap[cacheKey] = cachedInstance
}

子级应用:
1.main.js中mount(props)挂载方法中获取父级应用缓存的实例数据(router/isAddTab/getMicroAppCache)

import Vue from 'vue'
import App from './App.vue'
// import router from './router'
import routes from './router'
import RcAgGrid from '@redcarp/aggrid'
Vue.use(RcAgGrid)
import '@/assets/lib/webfonts/iconfont.css'
import '@it-web/element-ui/lib/theme-chalk/index.css'
import '@/assets/lib/index.css'
import '@/assets/styles/main.css'
import store from './store/store'
import './utils'
import './api/http'
import i18n from './assets/language/index'
import '@/utils/viewport'
import './utils/buryingPoint' // 火山引擎埋点
// import ElementUI from '@it-web/element-ui'
// import locale from '@it-web/element-ui/lib/locale/lang/zh-CN'
import VueRouter from 'vue-router'
import '@/directive/dialog'
import {
  getCurrentTime
} from '@redcarp/utils'
import {
  isNotExistInTab
} from '@/utils/common'
import actions from './actions'
import * as moment from 'moment'
import './components'
import RcCommon from '@redcarp/common'
import '@redcarp/common/redcarp-common.css'
import regularRules from '@/utils/regularRules' // 正则规则配置文件
import Cookies from 'js-cookie'
import { getUserInfo } from '@/api/user'
Vue.use(RcCommon)
Vue.prototype.$moment = moment
Vue.prototype.$getCurrentTime = getCurrentTime

// input-number精度,物料数量精度为0
Vue.prototype.$inputNumberPrecision = 0
Vue.prototype.$isNotExistInTab = isNotExistInTab
Vue.config.productionTip = false
Vue.prototype.$regularRules = regularRules // 正则规则配置
// 修复replace跳转同一个页面报错
const VueRouterReplace = VueRouter.prototype.replace
VueRouter.prototype.replace = function replace(to) {
  return VueRouterReplace.call(this, to).catch(err => err)
}

let router = null
let instance = null
let mainService = null

async function render(mainData) {
  const cachedInstance = mainData?.getMicroAppCache('declareManage') // 缓存的VNode
  let cachedNode = null
  router = new VueRouter({
    base: window.__POWERED_BY_QIANKUN__ ? '/declareManage/' : process.env.BASE_URL,
    mode: 'history',
    routes
  })
  router = initRouter(router) // 路由判断
  if (cachedInstance) {
    cachedNode = cachedInstance._vnode // 缓存的VNode
    router.apps.push(...cachedInstance.$router.apps)
  }
  if (cachedInstance) { // 存在缓存则判断是否需要跳转路由
    router.onReady(() => {
      const { path, query } = router.currentRoute
      const { path: oldPath } = cachedInstance.$router.currentRoute
      /*
      * 以下代码解释:子应用实例不注销,导致当path === oldPath时页面不触发activated生命周期
      * 使用中转页面
      */
      // 当前路由和上一次卸载时不一致,则切换至新路由
      if (path !== oldPath) {
        cachedInstance.$router.push({ path, query })
      } else {
        cachedInstance.$router.push({ path: '/index', query })
        Vue.nextTick(() => {
          cachedInstance.$router.push({ path, query })
        })
      }
    })
  }
  instance = await new Vue({
    router,
    store,
    i18n,
    render: cachedNode ? () => cachedNode : h => h(App) // 优先使用缓存vnode
  }).$mount(mainData && mainData.container ? mainData.container.querySelector('#repairCore') : '#repairCore')
  // 调用主应用store的方法
  if (mainData) {
    await mainData.data.store.dispatch('user/childAppLoadFinish')
  }
}

if (!window.__POWERED_BY_QIANKUN__) {
  render()
}
function initRouter(router) { // 路由拦截
  router.beforeEach((to, from, next) => {
    // 门户跳转token
    if (to.query.accesstoken) {
      Cookies.set('dahua_token', to.query.accesstoken)
      localStorage.setItem('token', to.query.accesstoken)
    }
    if (!window.__POWERED_BY_QIANKUN__) {
      if (to.query.token) {
        const dataToken = to.query.token
        Cookies.set('dahua_token', dataToken)
      }
      if (Cookies.get('dahua_token')) {
        // 获取用户信息
        if (localStorage.getItem('userInfo')) {
          store.dispatch('user/setMicroUserInfo', JSON.parse(localStorage.getItem('userInfo') || '{}') || {})
          localStorage.setItem('languageCode', localStorage.getItem('languageCode') || 'zh_CN')
          next()
        } else {
          getUserInfo().then(res => {
            if (Number(res.resultCode) === 200) {
              store.dispatch('user/setMicroUserInfo', res.data)
              localStorage.setItem('languageCode', res.data.languageCode)
              next()
            }
          })
        }
      } else {
        if (Cookies.get('dahua_token')) {
          // 获取用户信息
          getUserInfo().then(res => {
            if (Number(res.resultCode) === 200) {
              store.dispatch('user/setMicroUserInfo', res.data)
              localStorage.setItem('languageCode', res.data.languageCode)
              next()
            }
          })
        } else {
          next()
        }
      }
    } else {
      next()
    }
  })
  return router
}

export async function bootstrap() {
  console.log('vue app bootstraped')
}

export async function mount(props) {
  actions.setActions(props)
  store.dispatch('user/setMicroUserInfo', props.data.store.state.user.userInfo)
  Vue.prototype.$microProps = props
  Vue.prototype.$parentRouter = props.data.router
  Vue.prototype.$isAddTab = props.isAddTab
  Vue.prototype.$setAddTab = props.setAddTab
  mainService = props
  render(props)
}
// 应用每次 初出/卸载 会调用的方法,通常卸载微应用的应用实例
export async function unmount() {
  mainService.unmountCache('declareManage', instance) // 主应用进行缓存子应用的VNode
}


2.render 方法中可以通过调用父级应用中获取缓存子应用的方法getMicroAppCache拿到子应用虚拟节点 判断是否有缓存 在new Vue 初始化子应用实例
时优先使用缓存节点
3.main.js中 unmount 卸载的时候调用父级应用中unmountCache方法卸载缓存子应用


 

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue中,切换tab时可能会遇到重复加载数据的问题,主要原因是每次切换tab时都会触发组件的created或mounted钩子函数,从而重新加载数据。 为了解决这个问题,可以采取以下几种方案: 1. 使用keep-alive组件:使用keep-alive组件可以对已经加载的组件进行缓存,当切换tab时,被缓存的组件不会被销毁,再次切换回来时不会重新加载数据。可以在需要缓存的组件外包裹<keep-alive>标,实现组件的缓存。 2. 使用activated钩子函数:activated钩子函数是在被keep-alive缓存的组件进入时触发的,可以在该钩子函数中判断是否需要重新加载数据。如果需要重新加载数据,可以在activated钩子函数中发送请求或调用方法来获取最新的数据。 3. 使用v-show指令:使用v-show指令可以根据条件动态显示或隐藏组件,而不是销毁和重新创建组件。当切换tab时,通过v-show来判断是否需要显示组件,可以避免重复加载数据。 4. 使用vuex管理数据:将需要在不同tab之间共享的数据存储在vuex的状态管理中,这样无论在哪个tab中进行数据的修改,都会同步更新状态,切换tab时不会重新加载数据。 综上所述,解决vue切换tab数据重复加载问题的方法有很多,可以根据实际情况选择适合的方案。保持组件的缓存、自主控制数据加载时机、条件显示组件和使用状态管理工具等都是常见的解决方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值