Vue2中keep-alive与手动缓存列表页参数

本次需求:

当前列表页可进行条件搜索,有一些操作例如:查看详情,编辑等需要跳转路由。现在是想要在返回列表页时保留之前的搜索项等

需要解决的问题:

1.详情页面,或者编辑页但是不进行编辑直接返回

2.编辑操作成功之后进行返回。

解决思路:

第一种场景:没有对数据进行任何操作,可以看做是只进行了查看,这类问题可以用keep alive解决

第二种场景:对数据进行了操作,所以返回列表页的时候必须保证列表页数据时最新的状态。比如当前数据是暂存状态,是可以对数据进行修改的,也就是列表页有个修改按钮,这个按钮是只有暂存状态才应该展示。当前数据修改提交完成后,应该是没有修改按钮的,如果用keep alive的话数据还是旧的数据和状态,这样会导致依然存在修改按钮,所以这种场景中需要刷新表格,也就是需要把搜索项和分页等列表页的参数进行保存。
这两种场景下文为了方便可能统一称呼为缓存起来。

具体的解决步骤和遇到的问题

在实现之前需要明白,虽然是两种方式。但是实际中第一种场景可单独存在(只是详情页面,没有对数据进行修改的操作),第二种场景必定与第一种共存(因为你的比如修改页码,可以进行修改,但是也可以不修改直接返回)
如下的所有代码基本都是伪代码,可借鉴思路,具体实现还是要根据自己的实际情况进行修改。(因为我有部分实现就是和自己的逻辑组件之类的耦合在了一起,主要是因为懒,就删删减减复制了过来)

代码块中的注释为了不出现滚动条所以很多分成了两行,希望不会影响阅读体验

keep alive

通过keep alive的include设置都有哪些页面需要进行缓存,这个keepAliveList数组(需要被缓存页面name所组成的)保存在vuex中

store/modules/keepAlive.js

const state = {  
  keepAliveList: []
}

const mutations = {  
  SET_KEEP_ALIVE_LIST: (state, pageName) => {  
    if (!state.keepAliveList.includes(pageName)) {
      state.keepAliveList = [...state.keepAliveList, pageName]    
    }  
},
  DEL_KEEP_ALIVE_LIST: (state, pageName) => {
    if (state.keepAliveList.includes(pageName)) {
      const index = state.keepAliveList.findIndex(item => item === pageName)
      state.keepAliveList.splice(index, 1)
    }
  }
}

keep alive遇到的问题:

最开始的基本思路是:

在list页面做判断,如果去往的页面是detail页面,那么缓存list页面,否则删除。



list页面

beforeRouteLeave(to, from, next) {
  if(to.path === '详情') {
    this.$store.commit('keepAlive/SET_KEEP_ALIVE_LIST', this.$option.name)
  } else {
    this.$store.commit('keepAlive/DEL_KEEP_ALIVE_LIST', this.$option.name)
  }
  next()
}



这种实现方式出现的问题:

第一次从list页面跳转详情,从详情返回可以正常缓存。如果是第二次从list页面跳转详情,从详情返回list页面会发现既触发created,又触发了activated

后来发现其实是思路错了,改为在进入list页面的时候进行缓存,如果跳转的不是detail页面,那么删除当前页面的缓存

beforeRouteEnter(to, from, next) {
  next(vm => {
    vm.$store.commit('keepAlive/SET_KEEP_ALIVE_LIST', vm.$options.name)
  })
},
beforeRouteLeave(to, from, next) {
  if (to.path !== '详情') {
    this.$store.commit('keepAlive/DEL_KEEP_ALIVE_LIST', this.$options.name)
  }
  next()
}

保留搜索条件:

点击查询的时候把当前页面的搜索参数和页码存在vuex中,然后在当前list页面判断vuex中是否有搜索项,如果有的话会搜索这些条件。

这里面需要注意的是:vuex中有数据,但是不是所有时候都需要搜索这些条件。只有是从当前list页面跳转出去,然后返回list页面才需要搜索条件



vuex代码:

SET_PAGE_PARAMS: (state, obj) => {
  Object.keys(obj).forEach(k => {
    state.pageParams = {
      [k]: {
        ...state.pageParams[k],
        ...obj[k]
      }
    }
  })
},
DEL_PAGE_PARAMS: (state, name) => {
  if (!name) return
  delete state.pageParams[name]
}



搜索区域所在页面或组件代码

// pageParams是除page和size之外的搜索条件
// 因为我的搜索和表格分属两个组件,所以保留参数这部分也分开了
this.$store.commit('keepAlive/SET_PAGE_PARAMS', {搜索条件})



表格区域所在页面或组件代码

created() {
  const parentName = this.$parent.$options.name
  if (Object.keys(this.pageParams).includes(parentName)) {
      const { searchCondition = {}} = this.pageParams[parentName]
      Object.keys(searchCondition).forEach((item) => {
      tableSearchParams[item] = searchCondition[item]
    })
  }
  if (this.pageParams[parentName]) {
    this.currentPage = this.pageParams[parentName].page || 1
    this.currentSize = this.pageParams[parentName].size || 10
  }
  this.getList({ initialParams: tableSearchParams })}
  
 // 同样是表格所在页面或组件代码,要在getList方法里面判断
 // 如果当前list页面的name在keepAliveList中的话,也就意味着这个页面需要被缓存
getList({ initialParams = {} } = {}) {
  const pageParams = {
    page: this.currentPage,
    size: this.currentSize
  }
  const parentName = this.$parent.$options.name
  if (this.keepAliveList.includes(parentName)) {
    const tempObj = {
      [this.$parent.$options.name]: pageParams
    }
    this.$store.commit('keepAlive/SET_PAGE_PARAMS', tempObj)
  }
...
}



list页面代码

// list页面原有的跳转路由代码中额外增加
// 这个needKeepAlive变量是否需要被缓存或者说是否需要保留搜索参数。
this.$store.commit('keepAlive/SET_NEED_KEEP_ALIVE', true)

// ---分割线---
created() {
  this.$store.commit('keepAlive/SET_NEED_KEEP_ALIVE', false)
},
activated() {
  this.$store.commit('keepAlive/SET_NEED_KEEP_ALIVE', false)
},
beforeRouteLeave(to, from, next) {
  // 这个routeList是list页面所有跳转出去的路由组成的数组。
  if (!this.routeList.includes(to.path) || !this.needKeepAlive) {
    this.$store.commit('keepAlive/DEL_KEEP_ALIVE_LIST', this.$options.name)
    this.$store.commit('keepAlive/DEL_PAGE_PARAMS', this.$options.name)
  }
// 从list页面调到详情或者编辑页面之后,只有返回当前list页面才有是否需要缓存这种考虑
// 如果不是返回当前list页面就把当前页面的搜索参数和keepAliveList对应清空就行
  if (this.needKeepAlive) {
    to.meta.isKeepAlive = true
    to.meta.fromPath = this.$route.path
    to.meta.fromName = this.$options.name
  }
  next()
}



详情或者编辑页面

beforeRouteLeave(to, from, next) {
  const { isKeepAlive = false, fromPath = '', fromName = '' } = this.$route.meta
  if (to.path !== fromPath || !isKeepAlive || !this.keepAliveMode) {
    this.$store.commit('keepAlive/DEL_PAGE_PARAMS', fromName)
    this.$store.commit('keepAlive/DEL_KEEP_ALIVE_LIST', fromName)
    return next()
  }
  if (this.keepAliveMode === 'update') {
    this.$store.commit('keepAlive/DEL_KEEP_ALIVE_LIST', fromName)
    return next()
  }
  next()
}

// 同时在操作成功返回中增加
this.keepAliveMode = 'update'

// 在单纯返回上一页面中增加
this.keepAliveMode = 'detail'

保留数据到这里就成功了,不过还有个东西要处理,就是search组件。如果有初始条件的话,需要展示这些默认值。(默认值展示部分就不做过多展开了。一般情况就是v-model的值变成你保存的数据即可)

search中一般而言了包含级联下拉这种情况,也就是选择了前一项下拉,根据值调用下一个下拉的接口。(这部分记得特殊处理,因为我这部分和我本身的search组件有点耦合太高,所以也没有复制过来。。。)

搜索条件默认展示时小问题

一般是先调用完下拉选项的接口,再赋默认值。我是相当于把所有的下拉选项接口保存在一个数组中,然后循环调用。
但是用forEach循环的话不能保证接口结束完再执行赋默认值,需要用for of,这部分就不额外展开了,关于await执行顺序问题可以参考:

阮一峰老师的es6入门教程

正确写法

created() {
  ...
  for (const item of cascadeArr) {
    const val = searchCondition[item.prop]
    await this.selChange(xxx)
  }
  // 这里再赋默认值
}

methods: {
  async selChange() {
    // 调用接口
    const res = await xxxxx()
    ....
  }
}



错误写法

created() {
  ...
  cascadeArr.forEach(item => {
    const val = searchCondition[item.prop]
    await this.selChange(xxx)
  })
  // 这里赋默认值并不能保证接口已经返回结果了
}

END

如果有看到这里的大佬有好的实现方法希望不吝赐教

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值