vue keep-alive,$on,$off,$emit来实现页面缓存且列表页单条数据局部刷新

543 阅读1分钟

一、为了提升用户提升用户体验,当列表页进入详情页时刷新数据,后退时不刷新且回到进入详情页时的位置,进入列表页时刷新列表数据;当详情页更新数据时,返回列表页时,不仅在原来的位置并且当条数据更新; 

 二、原理:A→B:B刷新;B→C:C刷新;C→B:B不刷新且在原位置,数据更新。 

       其中:A:其他页面;B:列表页;C:为详情页;

 三、我们先做A→B:B刷新;B→C:C刷新;C→B:B不刷新且在原位置;

     1.首先我们先在App.vue里这样写 

<template>
  <div id="app">
    <keep-alive>      
        <router-view v-if="$route.meta.keepAlive"/>    
    </keep-alive>    
    <router-view v-if="!$route.meta.keepAlive"/>
  </div>
</template>

    2.配置路由:src => router => index.js;lookjournal为B页面

export default new Router({
  mode: 'history',
  routes: [
    .
    .
    .
   {
      path: '/page/work/journal/lookjournal',
      name: 'lookjournal',
      component: lookjournal,
      meta: {
        title: '看日报',
        requiresAuth: true,
        isUseCache: false, // 是否更新页面
        keepAlive: true // 通过此字段判断是否需要缓存当前组件
      }
    },
    {
      path: '/page/work/journal/lookjournal/logDetails',
      name: 'logDetails',
      component: logDetails,
      meta: {
        title: '日报详情',
        requiresAuth: true,
      }
    },
    .
    .
    .
  ],
scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    } else {
      if (to.meta.keepAlive) {
        to.meta.savedPosition = document.body.scrollTop;
      }
      return {
        x: 0,
        y: from.meta.savedPosition || 0
      }
    }
  }
 
})

   3.B页面也就是lookjournal;其中logDetails为详情页也就是C页面

    // 列表页的beforeRouteLeave钩子函数
    beforeRouteLeave(to, from, next) {
      if (to.name == 'logDetails') {
        from.meta.isUseCache = true;
      } else {
        this.$route.meta.isUseCache = false;
      }
      next();
      this.$route.meta.isUseCache = false;
    },
    // 列表页组件的activated钩子
    activated() {
      // isUseCache为false时才重新刷新获取数据
      // 因为对列表页使用keep-alive来缓存组件,所以默认是会使用缓存数据的
      if (!this.$route.meta.isUseCache) {
        this.tabItem = []; // 清空原有数据
        this.getWhole(this.is_my, this.type_code, this.no_read, this.value)
      }
    },

    4.这样我们要的功能就实现了 A→B:B刷新;B→C:C刷新;C→B:B不刷新且在原位置

四、接下来做C→B:C操作后,B不刷新且在原位置且当条数据更新;

    1.先创建一个空白实例;eventBus.js

import Vue from 'vue'
let eventBus = new Vue({});
export default eventBus;

   2.在B和C页面分别引入eventBus.js

      C页面是这样的,也就是详情页logDetails

<script>
  import eventBus from '@/api/eventbus.js'
  export default {
    data() {
      return {
        articleId: this.$route.query.id,
      };
    },
  methods:{
    onClickLeft() {
       this.$router.back();
       eventBus.$emit('articleId', this.articleId)
     },
  }
 
 };
</script>

3.B页面是这样的,也就是列表页lookjournal

<script>
  import eventBus from '@/api/eventbus.js'
  export default {
    data() {
      return {
        tabItem: [],
      };
    },
    // 列表页的beforeRouteLeave钩子函数
    beforeRouteLeave(to, from, next) {
      if (to.name == 'logDetails') {
        from.meta.isUseCache = true;
      } else {
        this.$route.meta.isUseCache = false;
      }
      next();
      this.$route.meta.isUseCache = false;
    },
    // 列表页组件的activated钩子
    activated() {
      // isUseCache为false时才重新刷新获取数据
      // 因为对列表页使用keep-alive来缓存组件,所以默认是会使用缓存数据的
      if (!this.$route.meta.isUseCache) {
        this.tabItem = []; // 清空原有数据
        this.getWhole()//加载列表数据
      }
    },
    beforeDestroy() {
      //组件C$emit事件应在beforeDestory生命周期内。其次,组件B内的$on记得要销毁。
        eventBus.$off('articleId', this.getEventBus)
    },
    created() {
      eventBus.$on('articleId', this.getEventBus);//得到详情页传回来的值
    },
  methods:{
    onClickLeft() {
       this.$router.back();
     },
      getEventBus(data) {
        this.$toast.loading({
          duration: 0, // 持续展示 toast
          forbidClick: true,
          message: "加载中..."
        });
        this.getAxios('详情接口数据', {
          id: data,
        }).then((res) => {
          if (res.code == 1) {
            this.$toast.clear();
            for (let i = 0; i < this.tabItem.length; i++) {
              if (this.tabItem[i].id == data) {
                //得到当前的单条的列表数据详情更新缓存数据id一致的数据其他不变
              }
            }
          }
        }).catch(() => {})
      },
    getWhole(){
        //得到列表详情
        .
        .   
        .
    }
  }
 
 };
</script>

五、以上就是全部内容,欢迎大家指正错误或者提出不同的方案,