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 相关文章推荐
javascript function、指针及内置对象
Feb 19 Javascript
js限制文本框只能输入数字(正则表达式)
Jul 15 Javascript
jquery利用ajax调用后台方法实例
Aug 23 Javascript
jquery复选框checkbox实现删除前判断
Apr 20 Javascript
jQuery使用before()和after()在元素前后添加内容的方法
Mar 26 Javascript
JS+CSS实现的日本门户网站经典选项卡导航效果
Sep 27 Javascript
浅析Bootstrap缩略图组件与警示框组件
Apr 29 Javascript
详细解读Jquery各Ajax函数($.get(),$.post(),$.ajax(),$.getJSON())
Aug 15 Javascript
微信小程序 picker-view 组件详解及简单实例
Jan 10 Javascript
详解基于Angular4+ server render(服务端渲染)开发教程
Aug 28 Javascript
Vue CLI3 开启gzip压缩文件的方式
Sep 30 Javascript
谈谈JavaScript令人迷惑的==与+
Aug 31 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
生成sessionid和随机密码的例子
2006/10/09 PHP
php操纵mysqli数据库的实现方法
2016/09/18 PHP
js获取提交的字符串的字节数
2009/02/09 Javascript
jQuery 插件 将this下的div轮番显示
2009/04/09 Javascript
写出更好的JavaScript程序之undefined篇(中)
2009/11/23 Javascript
说明你的Javascript技术很烂的五个原因
2011/04/26 Javascript
通过上下左右键和回车键切换光标实现代码
2013/03/08 Javascript
js/jquery判断浏览器类型的方法小结
2015/05/12 Javascript
JavaScript用select实现日期控件
2015/07/17 Javascript
jQuery实现输入框下拉列表树插件特效代码分享
2015/08/27 Javascript
如何判断Javascript对象是否存在的简单实例
2016/05/18 Javascript
AngularJs bootstrap详解及示例代码
2016/09/01 Javascript
jQuery Validate验证表单时多个name相同的元素只验证第一个的解决方法
2016/12/24 Javascript
JavaScript中offsetWidth的bug及解决方法
2017/05/17 Javascript
nodejs集成sqlite使用示例
2017/06/05 NodeJs
微信小程序实战篇之购物车的实现代码示例
2017/11/30 Javascript
vue.extend实现alert模态框弹窗组件
2018/04/28 Javascript
使用vue-cli创建项目的图文教程(新手入门篇)
2018/05/02 Javascript
JS实现带阴历的日历功能详解
2019/01/24 Javascript
js 将线性数据转为树形的示例代码
2019/05/28 Javascript
如何用vue-cli3脚手架搭建一个基于ts的基础脚手架的方法
2019/12/12 Javascript
[43:57]LGD vs Mineski 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
[01:09:01]完美世界DOTA2联赛循环赛 Magma vs PXG BO2第一场 10.28
2020/10/28 DOTA
Python爬虫实现爬取京东手机页面的图片(实例代码)
2017/11/30 Python
PyCharm2019安装教程及其使用(图文教程)
2019/09/29 Python
Python爬虫爬取杭州24时温度并展示操作示例
2020/03/27 Python
查看已安装tensorflow版本的方法示例
2020/04/19 Python
Jupyter Notebook 实现正常显示中文和负号
2020/04/24 Python
Python进行特征提取的示例代码
2020/10/15 Python
html5 css3实例教程 一款html5和css3实现的小机器人走路动画
2014/10/20 HTML / CSS
城野医生官方海外旗舰店:风靡亚洲毛孔收敛水
2018/04/26 全球购物
将n个数按输入顺序的逆序排列,用函数实现
2012/11/14 面试题
人事主管的岗位职责
2013/11/16 职场文书
优秀员工个人的自我评价
2013/11/29 职场文书
教学器材管理制度
2014/01/26 职场文书
房地产公司财务总监岗位职责
2015/04/03 职场文书