从详情页返回列表页保持页码状态

3,314 阅读1分钟

需求

在使用elmenui的el-pagination时,用户从列表页如第二页进入详情页进行操作后,返回列表页时,列表应该显示第二页的内容,而不是第一页。

解决办法

1.使用路由跳转传参存储页码

从列表页跳转到详情页时,将当前页的页码再路由跳转时传递给详情页,再从详情页跳转回列表页时,传递回页码。

        // 从列表页跳转到详情页
        toDetial () {
            this.$router.push({ name: 'Detail', query: { pageNum: this.queryParams.pageNum } });
        },
        
        // 从详情页跳转到列表页 传递回页码
        toList () {
            this.$router.push({ name: 'List', query: { pageNum: this.$route.query.pageNum } });
        },
        
        //在列表页中获取页码
        created () {
            // 当路由参数不存在时 默认取第一页数据
            this.queryParams.pageNum = this.$route.query.pageNum || 1
            // 调用获取列表数据方法
            this.getListData()
        }

2.使用vuex存储页码

// 当页码变化时
        handleCurrentChange (val) {
            this.queryParams.pageNum = val;
            // 将当前页数保存到vuex中
            this.$store.commit('currentPage', val);
            this.getList();
        },
        // 从详情页返回时让当前页等于vuex中保存的页码数
        created () {
            this.queryParams.pageNum = Number(this.$store.state.pageNum) || 1;
            this.getList();
        },
        // 当访问的页面不是详情页时,初始化vuex中保存的当前页信息
        beforeRouteLeave (to, form, next) {
            if (to.name && to.name !== 'Detail') {
                this.$store.state.pageNum = undefined;
            }
            next();
        },

3.使用keep-alive组件缓存整个页面

1.根据是否需要缓存定义2个router-view

    // 需要缓存的组件
    <keep-alive >
        <router-view v-if="$route.meta.keepAlive"></router-view>
    </keep-alive>
    // 不需要缓存的组件
      <router-view  v-if="!$route.meta.keepAlive"></router-view>

2.在Router里定义好需要缓存的路由组件

    new Router({
    routes: [
        {
            path: '',
            component: Layout,
            redirect: '/goods',
            hidden: false,
            name: '商品管理',
            meta: {
                title: '商品管理',
                noCache: true,
                icon: 'documentation'
        },
        children: [{
                path: 'goods',
                component: () => import('@/pages/goods/index'),
                name: 'goodsList',
                meta: {
                    title: '商品列表',
                    keepAlive: true  //需要缓存
                }
        }, {
            path: 'goods/goodsDetail',
            component: () => import('@/pages/goods/goodsDetail'),
            hidden: true,
            name: 'goodsDetail',
            meta: {
                title: '商品详情',
                keepAlive: true  //需要缓存
            }
        },
        ...
    ]
})

3.activated和deactivated

被keepAlive包裹的组件,会多出2个生命周期钩子函数 activateddeactivated

activated在缓存的组件第一次渲染时会被调用,之后在每次缓存的组件被激活时调用,相当于小程序中的onShow()。

activated触发时机:

1.第一次进入缓存的组件时:activated在mounted之后,beforeRouteEnter回调执行之前被调用。

       beforeRouteEnter --> beforeCreated --> created --> beforeMount -->若从其他路由组件进入
     (组件销毁destroyed/或离开缓存deactivated)--> mounted --> activated --> beforeRouteEnter回调 

2.之后再次进入缓存的组件时:beforeCreate created beforeMount mounted 都不会触发,只会触发activated以及deactivated。

   beforeRouteEnter --> 组件销毁destroyed/或离开缓存deactivated --> activated -->  beforeRouteEnter回调

deactivated在每次离开缓存的组件时会被调用,相当于小程序中的onHide()。

deactivated触发时机:

1.如果离开的组件有缓存(被keepAlive包裹的路由组件),则执行deactivated,不会执行beforeDestroy以及destroyed。

    beforeRouteLeave --> beforeEach --> beforeRouteEnter--> afterEach --> deactivated

2.如果离开的路由组件没有缓存(不被keepAlive包裹的路由组件),则执行deactivated,beforeDestroy以及destroyed。

    beforeRouteLeave --> beforeEach --> beforeRouteEnter--> afterEach --> deactivated --> 
    beforeDestroy -->destroyed

4.按需缓存

    keep-alive props:
    include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
    exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
    max - 数字。最多可以缓存多少组件实例。

include 和 exclude prop 允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示。

keep-alive组件如果设置了include属性,则就只有和include匹配的组件会被缓存。

     <!-- 逗号分隔字符串 -->
    <keep-alive include="a,b">
      <router-view v-if="$route.meta.keepAlive"> </router-view>
    </keep-alive>
     <!-- 不需要缓存的视图组件 -->
    <router-view v-if="!$route.meta.keepAlive">  </router-view>
    
    <!-- 正则表达式 (使用 `v-bind`) -->
    <keep-alive :include="/a|b/">
      <router-view v-if="$route.meta.keepAlive"> </router-view>
    </keep-alive>
     <!-- 不需要缓存的视图组件 -->
    <router-view v-if="!$route.meta.keepAlive">  </router-view>
    
    <!-- 数组 (使用 `v-bind`) -->
    <keep-alive :include="['a', 'b']">
      <router-view v-if="$route.meta.keepAlive"> </router-view>
    </keep-alive>
    <!-- 不需要缓存的视图组件 -->
    <router-view v-if="!$route.meta.keepAlive">  </router-view>

在app.vue中监听路由变化

  export default {
  name: "app",
  data: () => ({
    include: []
  }),
  watch: {
    $route(to, from) {
      //如果 要 to(进入) 的页面是需要 keepAlive 缓存的,把 name push 进 include数组
      if (to.meta.keepAlive) {
        !this.include.includes(to.name) && this.include.push(to.name);
      }
      //如果 要 form(离开) 的页面是 keepAlive缓存的,
      //再根据 deepth 来判断是前进还是后退
      //如果是后退
      if (from.meta.keepAlive && to.meta.deepth < from.meta.deepth) {
        var index = this.include.indexOf(from.name);
        index !== -1 && this.include.splice(index, 1);
      }
    }
  }
};

总结:

只简单缓存页码可以使用路由跳转传参或者vuex存储页码,若想缓存整个页面,包括查询筛选条件等,则使用keep-alive组件。

另外,还可以使用sessionStorage存储当前页码,与使用vuex方法类似。

如果大家有更好的方法实现,欢迎讨论交流。