热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

vue单页应用前进刷新后退不刷新方案探讨

引言前端webapp应用为了追求类似于native模式的细致体验,总是在不断的在向native的体验靠拢;比如本文即将要说到的功能,native由于是多页应用,新页面可以启用一个的

引言

前端webapp应用为了追求类似于native模式的细致体验,总是在不断的在向native的体验靠拢;比如本文即将要说到的功能,native由于是多页应用,新页面可以启用一个的新的webview来打开,后退其实是关闭当前webview,其上一个webview就自然显示出来;但是在单页的webapp应用中,所有内容其实是在一个页面中展示的,不存在多页的情况,这时就需要前端开发来想办法实现相应的体验效果。

首先需要说明一下,本文所说的前进刷新后退不刷新是指组件是否重新渲染,比如列表A页面,点击其中的每一项进入详情B页面,然后从B页面后退到列表A页面时,A页面没有重新渲染,也没有重新发送ajax请求。下面,我们就来说说在vue的单页应用中,实现前进刷新后退不刷新的一些实现方案,其他的方案大家可以一起补充。

keep-alive方案

keep-alive是vue官方提供的一种缓存组件实例的方法,vue官网对其用法的介绍:

包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。

正如vue官网的介绍,我们在开发中就可以使用他这一点来缓存后退不用刷新的路由组件。具体的实现思路如下。

1、模板中使用keep-alive来缓存对应的路由组件

在app.vue模板中改写,具体可以这样:


    
        
    



    

这种方式需要通过vue路由元信息的配合,当然也可以像下面这样:


    
        
    

这种方式缺点是:

需要事先知道路由组件的**name**值,这在大型项目中不是一个特别好的选择。

2、在路由配置文件中配置路由元信息

下面以第一种模板方式来展开介绍。对应上面模板文件中的路由元数据配置如下:

routes: [{
        path: '/',
        name: 'home',
        component: Home,
        meta: {
            keepAlive: false //此组件不需要被缓存
        }
    },
    {
        path: '/list',
        name: 'list',
        component: List,
        meta: {
            keepAlive: true //此组件需要被缓存
        }
    },
    {
        path: '/detail',
        name: 'detail',
        component: Detail,
        meta: {
            keepAlive: false // 此组件需要被缓存
        }
    }
]

3、在keep-alive组件提供activated钩子函数实现数据更新逻辑

需要强调的是keep-alive组件(这里是指keep-alive包裹的路由组件,下同)与一个vue组件是有区别的,vue的具体生命周期函数可以参考这里;而keep-alive组件,除了正常vue组件提供的生命周期之外,其额外新增了2个跟keep-alive相关的钩子函数:

  • activated: 缓存的组件再次进入时会触发
  • deactivated: 缓存的组件离开时会触发

既然keep-alive组件提供了这么多生命周期函数钩子,那么这些钩子函数具体的执行顺序是怎样的呢?

第一次进入keep-alive组件时,其生命周期执行顺序:

beforeRouteEnter --> created --> mounted --> activated --> deactivated

非首次进入时,其生命周期执行顺序:

beforeRouteEnter -->activated --> deactivated

可以看到,非首次进入keep-alive组件时,正常的vue组件生命周期函数是不会在执行,而会执行keep-alive新增的两个周期钩子函数。同时也可以看出离开keep-alive组件时其destroy周期函数并没有执行,从侧面证明缓存组件并没有销毁。根据介绍,我们可以:

通过利用keep-alive提供activated钩子函数来决定是否进行ajax请求来更新组件,以及deactivated钩子函数来重置页面相关状态。

keep-alive实现后推不刷新的方案,有一些地方需要特别注意:

  • keep-alive组件的更新时机要有清晰的认知

意思就是在开发过程中需要知道后退不刷新组件虽然不重新渲染,但是要知道组件数据在什么情况下需要重新发送ajax请求来获取数据,从而更新组件。

就拿上面的A、B页面来说,我们需要知道列表A页面对应的keep-alive组件在什么时候进行更新,因为进入A页面的入口可以是从B页面后退而来,也可能从其他页面前进而来;当然需要对这两种不同情况需要加以区分,否则A页面的数据就一直是第一次缓存过的数据。

这篇文章给出了一种解决方案:

首先,在每个路由元信息meta中添加一个isBack字段,用来解决beforeRouterEnter不能直接访问vue实例。

    ...
    {
        path: '/list',
        name: 'list',
        component: List,
        meta: {
            keepAlive: true, //此组件需要被缓存
            isBack: false
        }
    }
    ...

然后,借助beforeRouteEnter钩子函数来判断页面来源:

    beforeRouteEnter(to, from, next) {
      if(from.name === 'detail') { //判断是从哪个路由过来的,若是detail页面不需要刷新获取新数据,直接用之前缓存的数据即可
          to.meta.isBack = true;
      }
      next();
    },

最后,需要借助keep-alive提供钩子函数activated来完成是否更新:

  activated() {
    if(!this.$route.meta.isBack) {
      // 如果isBack是false,表明需要获取新数据,否则就不再请求,直接使用缓存的数据
      this.getData(); // ajax获取数据方法
    }
    // 恢复成默认的false,避免isBack一直是true,导致下次无法获取数据
    this.$route.meta.isBack = false
  },
  • keep-alive组件前进的页面刷新导致keep-alive组件状态丢失

继续以上面的A、B页面为例,在进入详情B页面后,然后刷新,这时列表A页面的缓存的数据都丢失了,由于上面的判断规则也会导致不会重新获取数据。所以对于这种问题,还需要额外加一些判断条件。由于keep-alive第一次进入时会执行created方法,所以利用这点加一个标识来加以判断:

   //第一次进入keep-alive路由组件时
    created() {
      this.isFirstEnter = true;
     // 只有第一次进入或者刷新页面后才会执行此钩子函数,使用keep-alive后(2+次)进入不会再执行此钩子函数
   },

activated钩子函数也需要增加对应的判断:

  activated() {
     if(!this.$route.meta.isBack || this.isFirstEnter){
         // 如果isBack是false,表明需要获取新数据,否则就不再请求,直接使用缓存的数据
         // 如果isFirstEnter是true,表明是第一次进入此页面或用户刷新了页面,需获取新数据
         this.data = ''// 把数据清空,可以稍微避免让用户看到之前缓存的数据
         this.getData();
     }
     // 恢复成默认的false,避免isBack一直是true,导致下次无法获取数据
     this.$route.meta.isBack=false
     // 恢复成默认的false,避免isBack一直是true,导致每次都获取新数据
     this.isFirstEnter=false;
   },
  • 缓存过多keep-alive组件,因常驻内存会导致内存占用过多

这是一个特别需要注意的问题,尤其是当整个系统或者系统大部分页面都使用keep-alive来缓存组件时,由于其是缓存在内存中的,若不加处理,内存堆积越来越大,导致系统卡顿。正确的解决方案是:需要及时销毁掉内存缓存的组件

具体可以参考:vue issue#6509和记一次vue 的keep-alive踩坑之路两篇文章的实现思路。

嵌套路由

嵌套路由具体的实现可以参考官网,这种方案也是一种解决思路。下面以一个具体的例子(如下图所示)来说一下实现的具体过程。

正如上图所示,一个下单页面有6处跳出当前页面查看规则、协议或者修改具体某些内容的页面,因为这6项依赖这个订单页,那么可以使用路由嵌套来实现这种后退不刷新的过程,下单页作为父路由,其他跳转项可以作为其子路由。具体步骤:

1、配置路由信息

    {
      path: '/order',
      component: Order,
      children: [
        {
          path: 'invoice',
          component: Invoice
        }, {
          path: 'contact',
          component: Contact
        },
        {
          path: 'costrule',
          component: CostRule
        }, {
          path: 'refundrule',
          component: RefundRule
        },{
          path: 'useragreement',
          component: UserAgreement
        },{
          path: 'payrule',
          component: PayRule
        }
      ]
    }

2、在下单页Order组件模板中配置路由嵌套。

    

这样,通过下单页进入其他页面比如进入修改联系人信息页面,那么路由从/order进入到/order/contact,修改完成后回退会回到父路由/order中,完成后推不刷新的功能。

当然,正如上面所说的,嵌套路由方案只是一种可选择方案,有其对应的使用场景;另外,使用过程还需要注意以下几点:

**1、进入子路由后,若是在子路由强制刷新后,父子路由的组件都会重新渲染,执行各自路由组件的生命周期;父路由中设置相关逻辑都会执行。

**2、子路由若被其他页面共用,这时进入子路由时会触发第一点的情况,所以最好子路由是父路由独占的。

component组件配合路由方案

这种方案主要是利用vue提供的动态路由组件component来实现,页面组件的切换不再根据路由path来决定,而是根据不同的业务逻辑加载不同的动态组件。具体的实现可以参考这篇文章解决方案第6点部分:异步加载的业务线如何动态注册路由?。同样,同步路由也可以使用动态路由来完成对应后退不刷新功能。这不过这种方式的使用场景更急局限。

总结

上面提供的3种解决方案,第一种方案大家都比较熟悉,后面两种可能相对来说就比较陌生。它们只是解决同一问题的不同解决方案,想必还有其他的解决方案本人没有想到,有其他更好方案的可以一起探讨。

参考

1、滴滴 webapp 5.0 Vue 2.0 重构经验分享
2、另辟蹊径:vue单页面,多路由,前进刷新,后退不刷新
3、vue-router 之 keep-alive
4、记一次vue 的keep-alive踩坑之路
5、希望keep-alive能增加可以动态删除已缓存组件的功能


推荐阅读
  • 本文将介绍如何在混合开发(Hybrid)应用中实现Native与HTML5的交互,包括基本概念、学习目标以及具体的实现步骤。 ... [详细]
  • Flutter 核心技术与混合开发模式深入解析
    本文深入探讨了 Flutter 的核心技术,特别是其混合开发模式,包括统一管理模式和三端分离模式,以及混合栈原理。通过对比不同模式的优缺点,帮助开发者选择最适合项目的混合开发策略。 ... [详细]
  • 在寻找轻量级Ruby Web框架的过程中,您可能会遇到Sinatra和Ramaze。两者都以简洁、轻便著称,但它们之间存在一些关键区别。本文将探讨这些差异,并提供详细的分析,帮助您做出最佳选择。 ... [详细]
  • 本文档汇总了Python编程的基础与高级面试题目,涵盖语言特性、数据结构、算法以及Web开发等多个方面,旨在帮助开发者全面掌握Python核心知识。 ... [详细]
  • Google排名优化-面向Google(Search Engine Friendly)的URL设计 ... [详细]
  • 本文详细介绍了如何在现有的Android Studio项目中集成JNI(Java Native Interface),包括下载必要的NDK和构建工具,配置CMakeLists.txt文件,以及编写和调用JNI函数的具体步骤。 ... [详细]
  • Web App vs Native App:未来的移动应用趋势
    随着移动互联网的发展,Web App和Native App之间的竞争日益激烈。对于开发者而言,选择哪一种技术路径更为明智?本文将深入探讨两种应用模式的特点及未来趋势。 ... [详细]
  • 针对上一期关于 Windows 8 的问题,我们正在积极解决。本文提供 IE6,7,8 三个版本的单文件版下载,适用于 Windows Vista/7 系统,支持 x86 和 x64 架构。欢迎大家下载并分享。 ... [详细]
  • 如何在UIWebView中加载本地图片
    本文详细介绍了如何在UIWebView中加载本地图片的方法,这对于需要在应用内展示静态页面和富文本内容的场景非常有用。 ... [详细]
  • 深入对话上海视九叶文鑫:HTML5技术引领智能电视新趋势
    深入对话上海视九叶文鑫:HTML5技术引领智能电视新趋势 ... [详细]
  • 本文探讨了使用React Native框架开发的应用,在通过AppCenter构建iOS版本时遇到的‘CopyPlistFile’命令失败的问题,并提供了详细的解决方案。 ... [详细]
  • 如何使用Ionic3框架创建首个混合开发应用
    混合开发是指结合原生(Native)与网页(Web)技术进行移动应用开发的方法。本文将详细介绍如何利用Ionic3这一流行的混合开发框架,从环境搭建到创建并运行首个应用的全过程。 ... [详细]
  • 利用Java与Tesseract-OCR实现数字识别
    本文深入探讨了如何利用Java语言结合Tesseract-OCR技术来实现图像中的数字识别功能,旨在为开发者提供详细的指导和实践案例。 ... [详细]
  • 在开发一款应用程序时,我需要向用户提供一系列URL列表。为了提高用户体验,计划根据Wi-Fi状态预先加载这些URL,以便用户在点击时能够迅速访问内容,特别是在连接到Wi-Fi的情况下。 ... [详细]
  • 本文详细介绍了在CentOS 7上构建DNS解析服务器的步骤与配置方法。DNS系统不仅负责将主机名(域名)转换为相应的IP地址(正向解析),还能够根据IP地址反查主机名(反向解析)。此外,文章还探讨了不同类型的DNS服务器,如缓存域名服务器的作用和配置要点。通过本指南,读者可以全面了解并成功搭建一个高效稳定的DNS解析环境。 ... [详细]
author-avatar
涛涛哈帅_365
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有