vue项目详情页返回列表,记录之前信息

需求场景:

我们在开发后台管理系统的时候,经常会遇到这样的问题,我刚通过筛选条件筛选出来了一批数据,然后我点击到了第二页,点击进入了对应数据的详情页,查看完数据后,返回列表,这个时候之前筛选的信息不见了,页码也回到了第一页;这个时候如果需要再筛选,再重复操作的话,这样的体验是非常差的,很浪费时间;最好的体验是:我去详情之前是怎样的页面,详情返回后就是怎样的页面,保留之前的筛选条件、列表数据、分页信息等,甚至刷新也都保存之前的筛选条件;但是如果我从其他模块进入,我希望筛选条件等是清空的,从第一页开始;

具体展示如下:

image

解决方案:

方案一:将筛选条件与分页信息放到url链接中

因为该方案较简单,也是最易懂的,所以这边就不多赘述;

优点:

1、简单粗暴;

2、刷新后也是能保存筛选的条件

缺点:

1、如果筛选条件比较多,链接会很长;

2、因为链接中有很多信息,不太安全与美观;

3、对于面包屑导航栏不好实现;因为面包屑导航栏中不光是对应的路由,还要把对应参数都要拼接上去,会非常麻烦

方案二:使用子路由实现,一层一层覆盖上去

因为该方案也是比较简单,所以这边也不多赘述;

优点:

1、是最简单的,不需要做什么其他操作

缺点:

1、如果该模块有好几层,那路由设计时候就会很复杂,而且必须层层嵌套;嵌套多层会有性能问题

2、刷新之后就恢复之前的数据了;如果做本地存储的话会非常麻烦

方案三:采用keep-alive

该方案能记录所有的操作,但是去复原会是非常麻烦的一个事情;意思就是:我不同模块切换,需要重制对应模块的筛选条件,这个时候必须手动去清数据;网上也有说使用keep-alive的 incloud来切换需要缓存的组建;但是在自己亲测后,发现存在缓存错乱的问题;也使用过离开后调用$destroy 销毁组建,但是一旦销毁过一次后,之后都不会缓存了;并且刷新后是不会保存之前的筛选条件与内容的;所以弃用

方案四:

最终还是使用vuex + mixins来实现这样的效果,并且是非常简单;

思路:

1、刚开始想每个组件的筛选参数都存一份,把所有的筛选信息、分页信息、列表信息等都存到单独模块的store中,每次修改的时候去更新store信息;但是后来发现,如果模块很多,逻辑会非常复杂,代码量也会非常多;后来做了统一存储在一个store中,然后需要的时候去存,不需要的时候去删,根据对应页面的routeName来做区分;

2、写一个专门用来处理该逻辑的mixins文件,里面放各个模块都会用到的生命周期函数与method函数;然后统一在函数中做更新数据的操作;

3、如何判断从store中拿已存储的值还是说拿初始值?这个判断是在beforeRouteEnter这个路由生命周期函数中进行,在该生命周期中通过to与from的path,判断了路由是前进还是后退,如果是前进,那拿默认的初始值,并且销毁store中存储的信息;如果是返回,则取store中存储的值;关于如何判断,待会儿会详细说明;

4、关于参数初始值,为了方便管理与复用,所以拉到了一个单独的js文件中,做统一管理;

5、所有需要实现这样功能的页面都引入该mixins文件,然后单个组件该怎么搞就怎么搞,不需要做特殊处理;

说了这么多屁话,直接撸代码:

具体实现:

各个列表,需要实现该功能的所有列表请求参数都放到该js文件中,方便统一管理并且赋值;

reqDataList.js

// 角色管理列表请求参数初始化数据
export let roleManageReqData = {
  type: '',
  searchContent: '',
  page: 1,
  pageSize: 10
}

// 角色详情列表请求参数初始化数据
export let roleDetailReqData = {
  type: '',
  searchContent: '',
  page: 1,
  pageSize: 10
}

// 用户管理列表请求参数初始化数据
export let userManageReqData = {
  type: '',
  searchContent: '',
  page: 1,
  pageSize: 10
}

这边路由设计是平级路由,但是path的命名是按模块嵌套来的,这样设计可以较方便的判断是前进还是后退;

routerMap.js

{
    path: '/userManage',
    name: 'userManage',
    title: '人员管理',
    meta: {},
    component: () => import('@/views/peopleManage/userManage/index.vue'),
  },
  {
    path: '/userManage/addUser',
    name: 'addUser',
    title: '新增用户',
    meta: {},
    component: () => import('@/views/peopleManage/userManage/addUser/index.vue')
  },
  {
    path: '/roleManage/roleDetail',
    name: 'roleDetail',
    title: '角色详情',
    meta: {},
    component: () => import('@/views/peopleManage/powerManage/roleManage/roleDetail/index.vue')
  },
  {
    path: '/roleManage/roleDetail/roleEdit',
    name: 'roleEdit',
    title: '角色编辑',
    meta: {},
    component: () => import('@/views/peopleManage/powerManage/roleManage/roleDetail/roleEdit/index.vue')
  },
  {
    path: '/roleManage',
    name: 'roleManage',
    meta: {},
    component: () => import('@/views/peopleManage/powerManage/roleManage/index.vue')
  },
  {
    path: '/roleManage/addRole',
    name: 'addRole',
    title: '新增角色',
    meta: {},
    component: () => import('@/views/peopleManage/powerManage/roleManage/addRole/index.vue')
  }

列表混合页面;公共的一些函数、操作都放在这里面;这边说明一下混合中的beforeRouteEnter与组件中的beforeRouteEnter执行顺序,如下图:

image

所以在1中进行判断采用缓存还是初始化的值,然后赋值给路由meta信息;2中拿到对应的meta中的参数信息,请求接口,请求成功后next,在3中做对应的组件内部赋值等;在4中将对应组件的筛选条件的值赋值为第1步中的值;

pagitionMixin.js

import store from '@/store/index'
import * as reqDataList from '@/config/reqDataList'
export default {
  data() {
    return {
      reqData: {...reqDataList[this.$route.name + 'reqData']} // 根据当前routeName,获取对应初始化的参数
    }
  },
  beforeRouteEnter (to, from, next) {
    // 是否是返回;这边path设计是分层级的,如:列表的路由是:/list ,详情就是:/list/detail;这样就可以通过以下方式判断,是前进还是后退了
    let isBack = from.path.indexOf(to.path) > -1
    // 从store里面拿到存储的值
    let reqData = store.state.publicInfo.reqDataList[to.name]
    // 把reqData存储到对应路由的meta信息中,供单个组件beforeRouteEnter生命周期使用,解决没有next(),拿不到this的问题;
    to.meta.reqData = isBack && reqData ? reqData : {...reqDataList[to.name + 'reqData']}
    if (!isBack) {
      console.log('前进')
      // 如果是前进,则清除store中存储的该组建的数据
      store.dispatch('uploadListParams', {
        routeName: to.name
      })
    } else {
      console.log('后退', store.state.publicInfo.reqDataList[to.name])
    }
    next(vm => {
      // 请求参数做赋值
      vm.reqData = to.meta.reqData
    })
  },
  methods: {
    /**
     * @func 列表搜索
     */
    search () {
      console.log('搜索')
      this.reqData.page = 1
      store.dispatch('uploadListParams', {
        routeName: this.$route.name,
        reqData: this.reqData
      })
      this.getList ()
    },
    /**
     * @func 列表分页
     * @param val 当前第几页
     */
    currentChange (val) {
      console.log('分页')
      this.reqData.page = val
      store.dispatch('uploadListParams', {
        routeName: this.$route.name,
        reqData: {
          ...this.reqData,
          page: val
        }
      })
      this.getList (val)
    }
  }
}

单个组件内正常书写,这边只截取beforeRouterEnter中的代码;这边采用先请求,后next,是因为需要实现进度条效果;当该组件请求完成后,再切入到该路由中,可以达到与github一样的效果;

roleManage/index****.vue

beforeRouteEnter (to, from, next) {
  getUserList(to.meta.reqData).then(res => {
    next(vm => {
      vm.tableData = res.data.list
      vm.totalCount = res.data.totalCount
    })
  })
}

在store中处理对应筛选条件,对应路由的name为key,筛选参数对象为value,存储在reqDataList中;如果已经存在则更新,如果不存在则新增;如果没有传递reqData参数,则表示删除;每一次更新都同步一下sessionStorage中的数据,这边存储用于刷新后还是可以保留之前的筛选条件

publicInfo/index.js

import * as actions from './actions'
import * as getters from './getters'
import * as types from './types'

const publicInfo = JSON.parse(sessionStorage.getItem('publicInfo'))
const state = Object.assign({
  reqDataList: {}
}, publicInfo);

const mutations = {
  /**
   * 更新列表请求参数
   *
   */
  [types.UPLOAD_LIST_PARAMS](state, data) {
    try {
      // 判断是否有reqData,如果存在,表示是新增或者更新,不然则是删除
      if (data.reqData) {
        state.reqDataList[data.routeName] = data.reqData
      } else {
        delete state.reqDataList[data.routeName]
      }

      // 更新后的数据存储到本地
      sessionStorage.setItem('publicInfo', JSON.stringify(state));
    } catch (err) {
      console.log("存储错误:" + err)
    }
  }
}

export default {
  state,
  getters,
  actions,
  mutations
}

这样就能完美的实现该功能;具体的demo地址,请点击这里;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269