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

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

作者: 屎香味十足 | 来源:发表于2018-12-25 23:35 被阅读0次

    需求场景:

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

    具体展示如下:

    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地址,请点击这里;

    相关文章

      网友评论

          本文标题:vue项目详情页返回列表,记录之前信息

          本文链接:https://www.haomeiwen.com/subject/abqclqtx.html