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 UI的Dialog无法提交问题的解决方法
Jan 11 Javascript
将字符串转换成gb2312或者utf-8编码的参数(js版)
Apr 10 Javascript
单击复制文字兼容各浏览器的完美解决方案
Jul 04 Javascript
js操纵dom生成下拉列表框的方法
Feb 24 Javascript
js 获取元素下面所有li的两种方法
Apr 14 Javascript
js使用for循环与innerHTML获取选中tr下td值
Sep 26 Javascript
JavaScript通过prototype给对象定义属性用法实例
Mar 23 Javascript
深入探讨前端框架react
Dec 09 Javascript
gulp-uglify 与gulp.watch()配合使用时报错(重复压缩问题)
Aug 24 Javascript
JavaScript遍历Json串浏览器输出的结果不统一问题
Nov 03 Javascript
微信小程序自定义toast实现方法详解【附demo源码下载】
Nov 28 Javascript
Vue 第三方字体图标引入 Font Awesome的方法
Sep 28 Javascript
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
同时提取多条新闻中的文本一例
2006/10/09 PHP
PHP动态变静态原理
2006/11/25 PHP
PHP获取QQ达人QQ信息的方法
2015/03/05 PHP
PHP简单实现上一页下一页功能示例
2016/09/14 PHP
如何判断php mysqli扩展类是否开启
2016/12/24 PHP
基于jquery的实现简单的表格中增加或删除下一行
2010/08/01 Javascript
js移除事件 js绑定事件实例应用
2012/11/28 Javascript
jQuery cdn使用介绍
2013/05/08 Javascript
jQuery动态显示和隐藏datagrid中的某一列的方法
2013/12/11 Javascript
js 数值转换为3位逗号分隔的示例代码
2014/02/19 Javascript
javascript记录文本框内文字个数检测文字个数变化
2014/10/14 Javascript
PHP使用方法重载实现动态创建属性的get和set方法
2014/11/17 Javascript
js实现的动画导航菜单效果代码
2015/09/10 Javascript
KnockoutJS 3.X API 第四章之数据控制流component绑定
2016/10/10 Javascript
jQuery 插件封装的方法
2016/11/16 Javascript
nodejs+websocket实时聊天系统改进版
2017/05/18 NodeJs
python中的一些类型转换函数小结
2013/02/10 Python
Python中使用第三方库xlutils来追加写入Excel文件示例
2015/04/05 Python
python魔法方法-属性访问控制详解
2016/07/25 Python
linux平台使用Python制作BT种子并获取BT种子信息的方法
2017/01/20 Python
python模拟表单提交登录图书馆
2018/04/27 Python
python3+selenium自动化测试框架详解
2019/03/17 Python
python3的pip路径在哪
2020/06/23 Python
CSS3控制HTML元素动画效果
2014/02/08 HTML / CSS
HTML5 video标签(播放器)学习笔记(一):使用入门
2015/04/24 HTML / CSS
Zavvi美国:英国娱乐之家
2017/03/19 全球购物
Toppik顶丰增发纤维官网:解决头发稀疏
2017/12/30 全球购物
Farfetch台湾官网:奢侈品牌时尚购物平台
2019/06/17 全球购物
学生发电厂实习自我鉴定
2013/09/22 职场文书
文科生自我鉴定
2014/02/15 职场文书
《钱学森》听课反思
2014/03/01 职场文书
大学生活动总结怎么写
2014/04/29 职场文书
审计局2014法制宣传日活动总结
2014/11/01 职场文书
CSS中妙用 drop-shadow 实现线条光影效果
2021/11/11 HTML / CSS
Dubbo+zookeeper搭配分布式服务的过程详解
2022/04/03 Java/Android
JavaScript实现一键复制内容剪贴板
2022/07/23 Javascript