Vue.js中轻松解决v-for执行出错的三个方案


Posted in Javascript onJune 09, 2017

前言

Vue.js 是开源的一个前端开发库,通过简洁的 API 提供高效的数据绑定和灵活的组件系统。在前端纷繁复杂的生态中,Vue.js在近年来受到一定程度的关注,目前在 GitHub上已经有5000+。

本文是笔者在开发实践中踩过的坑,总结和分享出来,希望对大家学习Vue有所帮助。下面来看看详细的介绍:

【问题描述】

v-for遍历数组中存在空值导致页面报错,情况如下:

Vue.js中轻松解决v-for执行出错的三个方案

开发框架是以Vue为模型绑定的核心,根据错误可以进行一个简单的判断:

      ▪ removeChild操作既然不是发生在开发者显示书写的代码中,就应该是模型销毁后Vue引擎移除dom节点导致的。

      ▪ 错误栈信息都在框架的代码之内,此操作不可能是有用户代码触发导致的。

开发者某一流程的操作,会100%稳定地触发出这一错误,此错误导致js执行终端,整个程序陷入瘫痪无法工作,开发者的操作流程可以简化为如下的步骤:

      1. 访问视图A。

      2. 访问视图B。

      3. 回退历史记录到A。(错误发生在这里)

以上的跳转关系都是视图跳转,也就是发生在路由系统之内的路由跳转,按照路由逻辑,第三步的时候会依次执行视图的声明周期函数,包括:

      ▪ B视图的unRender逻辑,包括beforeUnRender和afterUnRender。

      ▪ A视图的Render,包括beforeRender和afterRender。

开发者只在beforeRender的阶段进行了模型重置的操作,几乎可以确定无疑,报错就是由这几行模型重置和赋值的操作引起的。层层排除可以寻找到使用简单代码重新此问题的方式。

【重现方式】

准备一个简单的空工程,新建视图test,一下的代码分别为js/view/test.js和html/view/test.html,js/view/test.js中视图对模型的操作可以完整反映重现此问题的流程。其中,setTimeout模拟的是ajax操作以让数据在多个tick之后设置到模型以观察Vue对dom节点的创建和销毁。

$nextTick之后,将test_arr置空的操作是为了使vue将此数据对应的dom节点销毁,对应代码如下:

Vue.js中轻松解决v-for执行出错的三个方案

以上的代码可以稳定重新问题,下面是解题思路。

【解决方案】

在不求甚解的状态下,这个问题是比较容易解决的,这里有几个临时的解决方案。

▲方案一

从报错信息Uncaught TypeError: Cannot read property 'removeChild' of null可知,之所以发生这个问题是因为在null的对象上执行了removeChild。

修改Vue框架代码,将这里的代码:

Vue.js中轻松解决v-for执行出错的三个方案

修改为:

Vue.js中轻松解决v-for执行出错的三个方案

▲方案二

深入地分析,为什么el.parentNode会是null,通过上面重现的步骤发现,当that.model.test_arr = ["","4","","5","6",""]这段代码设置发生后,v-for产生的dom节点之后3个,而不是5个,这种情况下el.parentNode就是不存在的,所以产生了第二种解决方案,强制不给空数据的元素生成dom节点。

Vue.js中轻松解决v-for执行出错的三个方案

▲方案三

问题并不算是圆满解决,正常的情况下框架应该具有鲁棒性,适应不同的使用场景,不应该出现js报错的问题,所以还有深入研究下去的必要。

在Vue中针对v-for指令有一个track-by的可选配置:

       ▪无track-by情况:数据修改时,无论值是否被修改,dom都被重新渲染。

       ▪有track-by情况:数据修改时,不变数据所在的dom不被重新渲染,已改变的数据所在dom才被重新渲染。

因为 v-for 默认通过数据对象的特征来决定对已有作用域和 DOM 元素的复用程度,这可能导致重新渲染整个列表。但是,如果每个对象都有一个唯一 ID 的属性,便可以使用 track-by 特性给 Vue 一个提示,Vue因而能尽可能地复用已有实例。所以就有了第三种解决方案。

Vue.js中轻松解决v-for执行出错的三个方案

【原因分析】

v-for遍历数组中存在空值导致页面报错,主要是遍历条件里对值的判断有问题。Vue为了保证对dom节点的复用,内置了一份按照id存取的dom缓存,通过对数据分析出dom_id,然后根据此id从缓存中获取dom节点。由于不同的数据取到了相同的dom_id,所以没有创建dom节点出来。但是,在最终数组置空,模型变更之后dom节点移除的时候却为这些dom节点触发了remove操作,也就是方案一中兼容的那些代码:

Vue.js中轻松解决v-for执行出错的三个方案

所以问题必定出现在getTrackByKey这个函数的执行上,以下是getTrackByKey的代码:

Vue.js中轻松解决v-for执行出错的三个方案

Vue中对数据绑定的操作大大地提高了开发者应用开发的效率,但与此同时也伴随着一些不易察觉的问题,尤其如本文中问题的重现条件比较复杂的情况下,测试不一定可以覆盖到问题的触发条件,这个时候就需要开发人员多一分警惕。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
使用Jquery实现每日签到功能
Apr 03 Javascript
Bootstrap基础学习
Jun 16 Javascript
js+html5实现canvas绘制椭圆形图案的方法
May 21 Javascript
自动适应iframe右边的高度
Dec 22 Javascript
angular+bootstrap的双向数据绑定实例
Mar 03 Javascript
详解JS中的attribute属性
Apr 25 Javascript
react native带索引的城市列表组件的实例代码
Aug 08 Javascript
AngularJS 的$timeout服务示例代码
Sep 21 Javascript
ReactNative之FlatList的具体使用方法
Nov 29 Javascript
Javascript格式化并高亮xml字符串的方法及注意事项
Aug 13 Javascript
Vue自定义指令写法与个人理解
Feb 09 Javascript
javascript异步处理与Jquery deferred对象用法总结
Jun 04 jQuery
node.js中cluster的使用教程
Jun 09 #Javascript
vue bootstrap小例子一枚
Jun 09 #Javascript
详解webpack解惑:require的五种用法
Jun 09 #Javascript
Bootstrap输入框组件使用详解
Jun 09 #Javascript
Jquery+Ajax+xml实现中国地区选择三级联动菜单效果(推荐)
Jun 09 #jQuery
微信分享调用jssdk实例
Jun 08 #Javascript
浅谈vue实现数据监听的函数 Object.defineProperty
Jun 08 #Javascript
You might like
用PHP伪造referer突破网盘禁止外连的代码
2008/06/15 PHP
php中删除字符串中最先出现某个字符的实现代码
2013/02/03 PHP
sae使用smarty模板的方法
2013/12/17 PHP
js利用Array.splice实现Array的insert/remove
2009/01/13 Javascript
JavaScript 乱码问题
2009/08/06 Javascript
Jquery中获取iframe的代码
2011/01/11 Javascript
eval与window.eval的差别分析
2011/03/17 Javascript
jquery导航制件jquery鼠标经过变色效果示例
2013/12/05 Javascript
NodeJS学习笔记之Http模块
2015/01/13 NodeJs
JavaScript基础函数整理汇总
2015/01/30 Javascript
简述Jquery与DOM对象
2015/07/10 Javascript
JS实现兼容性好,带缓冲的动感网页右键菜单效果
2015/09/18 Javascript
Bootstrap每天必学之进度条
2015/11/30 Javascript
jQuery实现右键菜单、遮罩等效果代码
2016/09/27 Javascript
AngularJS中table表格基本操作示例
2017/10/10 Javascript
node跨域转发 express+http-proxy-middleware的使用
2018/05/31 Javascript
Vue如何使用混合Mixins和插件开发详解
2020/02/05 Javascript
easyUI 实现的后台分页与前台显示功能示例
2020/06/01 Javascript
详解JavaScript自定义函数
2020/07/29 Javascript
JavaScript实现手风琴效果
2021/02/18 Javascript
Python与Redis的连接教程
2015/04/22 Python
python实现下载文件的三种方法
2017/02/09 Python
python+pandas生成指定日期和重采样的方法
2018/04/11 Python
pandas DataFrame实现几列数据合并成为新的一列方法
2018/06/08 Python
python 3.7.0 安装配置方法图文教程
2018/08/27 Python
python3实现爬取淘宝美食代码分享
2018/09/23 Python
pytorch 利用lstm做mnist手写数字识别分类的实例
2020/01/10 Python
Keras 利用sklearn的ROC-AUC建立评价函数详解
2020/06/15 Python
PyChon中关于Jekins的详细安装(推荐)
2020/12/28 Python
北欧最好的童装网上商店:Babyshop
2019/09/15 全球购物
三好学生自我鉴定
2013/12/17 职场文书
采购意向书范本
2014/03/31 职场文书
高一军训决心书
2015/02/05 职场文书
《红领巾真好》教学反思
2016/02/16 职场文书
python3实现无权最短路径的方法
2021/05/12 Python
六个好看实用的 HTML + CSS 后台登录入口页面
2022/04/28 HTML / CSS