浅谈Vue路由快照实现思路及其问题


Posted in Javascript onJune 07, 2018

前言:无论构建SPA还是MPA,组件的状态是无法被保存下来的,这对于开发过程中问题的重现是比较麻烦的,因为总是会失去上下文环境,导致重现过程变得繁琐。于是想到了将Vue Component相关信息动态绑定在路由上。本文将给出其实现思路以及相关问题。

场景重现

在使用Vue开发完应用后,应用上线进入了测试阶段。测试人员测试出现问题后会对页面进行截图,并将页面地址和截图内容发送给开发人员进行bug的确定和修改。这是比较常规的方式,但这对开发人员是非常不友好的,因为开发人员拿到的URL地址时,即没有测试人员的本地数据,也需要通过繁琐的操作重新按照测试人员所填写的内容进行上下文环境的重现。为什么我们不能将这些数据保存下载,测试人员将URL发送给开发人员之后,开发者能很容易定位到上下文环境并进行错误的重现及调试。

为什么是URL

无论你的数据是保存在内存还是Store,亦或是存放在WebDB中,都会遇到一个问题:你永远都无法拿到测试人员的数据。那么唯一的方式就是通过URL来传输数据。因此,我们的构想是:当界面加载组件后,将组件的部分属性的变化公开到URL上,同时,组件在渲染时,读取URL后将值解析还原到组件上去。这样,即使不断的刷新页面,组件的状态也不会发生改变。

实现

于是,我们为这个功能编写了一个Vue插件,取名路由快照(router-snapshot),其实现代码如下:

// router-snapshot.js
// https://github.com/dankogai/js-base64
import { Base64 } from 'js-base64';

function beforeRouteEnterHandler (vm, {key, ext}) {
 // 获取路由绑定字段
 const routeBindKeys = vm.$options[ext] || [];
 // 获取路由绑定部分的加密字符串
 const routeParamsString = vm.$route.query[key];
 // 解密并转换为JSON
 let routeParamsJSON;
 try {
  routeParamsJSON = JSON.parse(Base64.decode(routeParamsString));
 }catch (e) {
  routeParamsJSON = {};
 }
 routeBindKeys.forEach(attr => {
  // 使用vue的是指方式,若浏览器没有缓存值,则获取组件默认值
  vm.$set(vm, attr, routeParamsJSON.hasOwnProperty(attr) ? routeParamsJSON[attr] : vm[attr]);
  // 追加属性反向监听,监听到的属性变化都会呈现在路由上
  vm.$watch(attr, (value) => {
   const query = vm.$route.query;
   let routeSnapshotValueJSON;
   try {
    routeSnapshotValueJSON = JSON.parse(Base64.decode(query[key]));
   }catch (e) {
    routeSnapshotValueJSON = {};
   }
   routeSnapshotValueJSON[attr] = value;
   const extendQuery = {};
   extendQuery[key] = Base64.encodeURI(JSON.stringify(routeSnapshotValueJSON));
   vm.$router.push({
    query: { 
     ...query,
     ...extendQuery
    }
   })
  }, {
   deep: true
  });
 })
}

export default {
 install (Vue, {key = '_', ext = 'routeShot'} = {}) {
  Vue.mixin({
   // beforeRouteEnter (to, from, next) {
   //  console.log('beforeRouteEnter', to, from)
   //  next(beforeRouteEnterHandler)
   // }
   created () {
    beforeRouteEnterHandler(this, {key, ext});
   }
  });
 }
}

代码逻辑大致如下:

  1. 代码45行,注册该组件时,我们需要指定保存在URL query部分的键名,默认为_;同时指定绑定在组件上的拓展属性名,默认为routeShot;
  2. 代码21行,根据组件拓展属性,对这些拓展属性实施监听,将属性值的变化同步到路由中;
  3. 代码19行,在组件created阶段,获取路由参数并解析成组件属性,并将属性值同步到组件中;
  4. 代码13、25、31行对路由上的参数进行Base64的加密和解密;

组件的代码仅仅需要追加routeShot的配置即可:

<template>
  <!-- 使用的iview库的Switch组件 -->
  <Switch v-mode="switchValue"></Switch>
</template>
<script>
 export default {
  // 配置routeShot,指定该组件的switchValue属性映射到URL中
  routeShot: ['switchValue'],
  data () {
   return {
    switchValue: false
   }
  }
 }
</script>

经过这样,无论你怎么刷新页面,被快照的属性都不会发生改变。另外,除了data属性,prop、computed属性也是可以绑定到URL上的。

什么时候用最适合?

目前来说,应用场景中最多的还是非安全性表单以及不需要持久化的数据。举几个例子:

  1. 表格中筛选项有很多的情况下,用户进行了大量的选择和填写操作,结果因为网络原因导致请求失败。待网络恢复后,用户重新刷新页面,先前的操作必须重新执行;一般情况中,用户不会随意更改浏览器的URL,在这种条件下,用户的刷新不影响上下文的环境,能给用户带来一定便利;
  2. 之前代码示例中,开关组件的值不交予服务端进行持久化,也是可以使用这种方式来保存操作的;

存在的问题

写完这个插件,面临了三个我认为比较重要的问题:

  1. 性能问题: 通过代码47-50行可以看出,早期设计是将插件应用在路由组件中的,但是在后期的测试和使用中,发现还有很多组件不是注册在路由中的,也就是父子组件,这样的组件无法被路由钩子拦截到,因此就将该函数混入到了所有组件的created函数中。当应用越来越大、组件越来越多的时候,这个性能未免有点令人担忧;
  2. 持久性问题: 当URL的query部分越来越大的时候,超过了URL的长度限制,那么组件属性的持久性将会被中断。但我们并不能保证该长度不会超过,这随着应用的增长是无法预料的。在前端中,我们没有找到对应的库能进行定长加密解密,如果能找到,这个或将被解决;
  3. 安全性问题: 一直找不到比较安全的加密解密方式,而且我觉得这样做是会有安全隐患,但不知道究竟哪种场景会让这种安全性问题暴露的最大;

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
autoPlay 基于jquery的图片自动播放效果
Dec 07 Javascript
jquery简单瀑布流实现原理及ie8下测试代码
Jan 23 Javascript
javascript游戏开发之《三国志曹操传》零部件开发(一)让静态人物动起来
Jan 23 Javascript
js实现的切换面板实例代码
Jun 17 Javascript
Bootstrap3学习笔记(二)之排版
May 20 Javascript
浅谈$('div a') 与$('div&gt;a')的区别
Jul 18 Javascript
解析微信JS-SDK配置授权,实现分享接口
Dec 09 Javascript
Vue中父子组件通讯之todolist组件功能开发
May 21 Javascript
webpack@v4升级踩坑(小结)
Oct 08 Javascript
基于vue的验证码组件的示例代码
Jan 22 Javascript
Vue.js 无限滚动列表性能优化方案
Dec 02 Javascript
vue实现日历表格(element-ui)
Sep 24 Javascript
JavaScript中click和onclick本质区别与用法分析
Jun 07 #Javascript
jQuery动态移除与增加onclick属性的方法详解
Jun 07 #jQuery
使用Vue-cli 3.0搭建Vue项目的方法
Jun 07 #Javascript
vue 国际化 vue-i18n 双语言 语言包
Jun 07 #Javascript
vue cli2.0单页面title修改方法
Jun 07 #Javascript
JS实现同一DOM元素上onClick事件与onDblClick事件并存的解决方法
Jun 07 #Javascript
JavaScript事件委托原理与用法实例分析
Jun 07 #Javascript
You might like
一些javascript一些题目的解析
2010/12/25 Javascript
点击页面其它地方隐藏该div的两种思路
2013/11/18 Javascript
JS对象转换为Jquery对象示例
2014/01/26 Javascript
JavaScript实现按Ctrl键打开新页面
2014/09/04 Javascript
jQuery中has()方法用法实例
2015/01/06 Javascript
javascript实现避免页面按钮重复提交
2015/01/08 Javascript
Ajax跨域实现代码(后台jsp)
2017/01/21 Javascript
jQuery模拟窗口抖动效果
2017/03/15 Javascript
Node.js服务器开启Gzip压缩教程
2017/08/11 Javascript
完美解决手机浏览器顶部下拉出现网页源或刷新的问题
2017/11/30 Javascript
Vue监听数据渲染DOM完以后执行某个函数详解
2018/09/11 Javascript
详解vue-cli 脚手架 安装
2019/04/16 Javascript
laravel实现中文和英语互相切换的例子
2019/09/30 Javascript
echarts饼图各个板块之间的空隙如何实现
2020/12/01 Javascript
[01:14]DOTA2亚洲邀请赛 ShowOpen
2015/02/07 DOTA
[38:27]完美世界DOTA2联赛PWL S2 Forest vs FTD.C 第二场 11.26
2020/11/30 DOTA
Python中使用多进程来实现并行处理的方法小结
2017/08/09 Python
详解python while 函数及while和for的区别
2018/09/07 Python
python统计指定目录内文件的代码行数
2019/09/19 Python
python多进程(加入进程池)操作常见案例
2019/10/21 Python
用python爬取历史天气数据的方法示例
2019/12/30 Python
tensorflow入门:TFRecordDataset变长数据的batch读取详解
2020/01/20 Python
python爬虫学习笔记之pyquery模块基本用法详解
2020/04/09 Python
基于HTML5 Canvas 实现弹出框效果
2017/06/05 HTML / CSS
波兰灯具、照明和LED购物网站:Lampy.pl
2019/03/11 全球购物
美国手工艺品市场的领导者:Annie’s
2019/04/04 全球购物
Helly Hansen工作服美国官方网上商店:为最恶劣的环境
2019/09/04 全球购物
英文版区域经理求职信
2013/10/23 职场文书
期末考试动员演讲稿
2014/01/10 职场文书
致跳高运动员加油稿
2014/02/12 职场文书
预备党员的自我评价
2014/03/12 职场文书
平面设计专业求职信
2014/08/09 职场文书
网络文明传播志愿者活动方案
2014/08/20 职场文书
爱的教育读书笔记
2015/06/26 职场文书
新学期主题班会
2015/08/17 职场文书
win11自动弹出虚拟键盘怎么关闭? Win11关闭虚拟键盘的技巧
2023/01/09 数码科技