开启 keep-Alive 缓存后,接口不二次调用,保留上一级数据问题

前言: 写此文章之前,经历了一天在项目上的折磨,由于我做的是用户端的商城,需求是嵌套N多层页面,从一级页面进入二级页面,滚动二级页面的内容到底部,保存位置,在进入三级页面,保存位置,第四级页面,保存位置…当用户不想看了,在返回上一级页面并滚动到点击时的位置。
由于保存位置需要开启 keep-alive 组件,此组件会缓存不活动的数据,那么此时 created/mounted 里的接口就不会再次调用,在返回上一级页面时,浏览器会渲染第一次进入时拿到的数据.,返回到首页,再次进入需求页面,还是保留之前的数据…



开启缓存 → 保留位置


// 1.router 中先写一个保存位置的方法
export default new Router({
scrollBehavior(to, from, savedPosition) {
    // 此处理返回的是 body 的滚动高度即 document.documentElement.scrollTop
    // 或document.body.scrollTop,而该项目body高度已限制死,实际是根容器#app内部在滚动
    // 故上述两个滚动高度属性无效,该处理函数无效,可在需要的页面修改body及#app容器的高度
    if (savedPosition) {
      console.log(
        '------------支持 history.pushState 的浏览器且是浏览器前进后退按钮(go(n)或back、forward)进行导航--------------')
      console.log(savedPosition)
      return savedPosition
    } else {
      console.log('------------不支持 history.pushState 的浏览器或不是浏览器前进后退按钮进行导航-------------')
      if (to.path === '/shop' && ['/ActivityIndex', '/activities','/oldForNew'].includes(from.path)) {
        // 从这几个页面进入首页时,如果路径有indexTop则使用路径的,
        // 没有则使用页面离开时在路由元里记录的高度
        let top = to.meta?.scrollTop
        if (
          to.query &&
          to.query.indexTop !== undefined &&
          to.query.indexTop !== ''
        ) {
          top = +to.query.indexTop
        }
        return { x: 0, y: top || 0 }
      } else {
        console.log()
        return { x: 0, y: 0 }
      }
    }
  },

// 2.配置页面,开启缓存
routes: [{
      path: '/themeActivities',
      name: '专题活动',
      component: themeActivities,
      meta: {
        // requireAuth: true,
        keepAlive: true, // 判断页面是否缓存
      },
    }]

})


解决方法1: this.$route.meta.keepAlive = false / true 手动关闭/开启缓存,但是会造成二级页面去三级页面,再返回二级页面时,不会再次调用接口的情况


mounted() {
    // 安卓嵌套H5
    if (navigator.userAgent.indexOf('greeMall.android') > -1) {
      window.nativeToJSTradeInSelfInfo = this.nativeToJSTradeInSelfInfo //获取userId,无论有值还是空值,都会执行
    } else if (navigator.userAgent.indexOf('greeMall.ios') > -1) {
      // iOS嵌套H5
      let _that = this
      storage.remove('iosUserId')
      window.AppUserId = function (androidParam) {
        storage.set('iosUserId', androidParam.androidUserId)
        _that.getData()
      }
    }else {
      this.getDate() // 调用接口
      this.$route.meta.keepAlive = false // 手动关闭缓存
    }
  },
  
activated() {
	this.$route.meta.keepAlive = false // 手动关闭缓存(组件被激活后,不能这样使用,无效的操作)
    let o = storage.get('newsTop') ? storage.get('newsTop') : 0
    document.getElementById('app').scrollTop = o
    storage.remove('newsTop')
 },

beforeRouteLeave(to, from, next) {
 this.$route.meta.keepAlive = true // 手动开启缓存
   let page =['/shopDetail','/couponCenter','/trial','/searchResult','/newLogin','/seckillList','/living'].includes(to.path)
    if (page){
      let top = document.getElementById('app').scrollTop
      storage.set('newsTop', top)
    }
    next()
  },
  

最终解决方法: 动态删除 keep-Alive 组件,
参考网上的链接:https://segmentfault.com/a/1190000015845117


// 3.通过导航守卫,来判断进入的页面有哪些需要记住位置
// 路由离开时( to 离开当前页面去往哪个页面 / from 来自哪个页面 / next(vm=>{}) 下一步操作 )
beforeRouteLeave(to, from, next) {
// start---此步骤非常重要!!!
// 页面离开时添加一个缓存的标识符(从首页/搜索页进入此页,动态删除缓存,不删除会造成页面刚进入时渲染之前的数据,在替换成新的数据,有一秒的延迟)
   storage.session.set('couponTag', this.$vnode.tag) 
// end---此步骤非常重要!!!

   let page =['/shopDetail','/couponCenter','/trial','/searchResult','/newLogin','/seckillList','/living'].includes(to.path)
    if (page){
      let top = document.getElementById('app').scrollTop
      storage.set('newsTop', top)
    }
    next()
  },

// 4. 激活此钩子,页面一进来就滚动到点击时的位置(不刷新页面)
activated() {
    let o = storage.get('newsTop') ? storage.get('newsTop') : 0 
    document.getElementById('app').scrollTop = o
    storage.remove('newsTop')
  },

// 5. 解决因为开启缓存,而造成 created/mounted 里的接口不调用的问题
beforeRouteEnter(to, from, next) {
    next(vm => {
      vm.getData()  // 路由一进来调用数据,这里写了方法,created/mounted 里的接口方法可以注释了
    })
  },

// 6. 在首页的 activated 钩子中动态删除 第3步 里面缓存的标识符。
// 从首页进入需求页面(themeActivities)此步很重要,不删会造成进入时会先渲染之前数据,在渲染新数据,一秒延迟
activated() { // 在 activated里面删除与 beforeRouteLeave 里删除都一样,只不过 beforeRouteLeave里面需要添加判断条件,参考 第7点
      let couponTag = storage.session.get('couponTag')?storage.session.get('couponTag'):''
      let vnodeTags = [storage.session.get('searchResultTag'),couponTag]
      vnodeTags.forEach(e=>{
        if (e) {
        let instanceList = this.$parent.$vnode.componentInstance.$children
        let instance = instanceList.filter(ins => ins.$vnode.tag === e)
        if (instance.length > 0) {
          instance.forEach(vm => {
            if (vm.$vnode && vm.$vnode.data.keepAlive) {
              if (
                vm.$vnode.parent &&
                vm.$vnode.parent.componentInstance &&
                vm.$vnode.parent.componentInstance.cache
              ) {
                if (vm.$vnode.componentOptions) {
                  var key = vm.$vnode.key == null ? 
                  vm.$vnode.componentOptions.Ctor.cid + (vm.$vnode.componentOptions.tag ? `::${vm.$vnode.componentOptions.tag}` : '')
                  : vm.$vnode.key
                  var cache = vm.$vnode.parent.componentInstance.cache
                  var keys = vm.$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]
                  }
                }
              }
            }
            vm.$destroy()
          })
        }
        storage.session.remove('searchResultTag')
        storage.session.remove('couponTag') // 删除标识符
      }
      })
      
    },

// 7. 搜索页去往需求页面 动态删除缓存节点
beforeRouteLeave(to, from, next) {
if(to.path =='/themeActivities'){
      let vnodeTag = storage.session.get('couponTag')
        if (vnodeTag) {
        let instanceList = this.$parent.$vnode.componentInstance.$children
        let instance = instanceList.filter(ins => ins.$vnode.tag === vnodeTag)
        if (instance.length > 0) {
          instance.forEach(vm => {
            if (vm.$vnode && vm.$vnode.data.keepAlive) {
              if (
                vm.$vnode.parent &&
                vm.$vnode.parent.componentInstance &&
                vm.$vnode.parent.componentInstance.cache
              ) {
                if (vm.$vnode.componentOptions) {
                  var key =
                    vm.$vnode.key == null ?
                    vm.$vnode.componentOptions.Ctor.cid +
                    (vm.$vnode.componentOptions.tag ?
                      `::${vm.$vnode.componentOptions.tag}` :
                      '') :
                    vm.$vnode.key
                  var cache = vm.$vnode.parent.componentInstance.cache
                  var keys = vm.$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]
                  }
                }
              }
            }
            vm.$destroy()
          })
        }
        storage.session.remove('couponTag')
      }
      }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值