vue报错Failed to execute 'appendChild' on 'Node'解决
muio 人气:0一、问题描述
某天在开发需求时发现,业务页面上报告了一个Script error。
由于vconsole看不到详细报错信息,于是在chrome上打开,具体报错信息如下:
Uncaught DOMException: Failed to execute 'appendChild' on 'Node': This node type does not support this method. at Object.appendChild
看起来是vue2.6.12包里报了一个错误,但从报错提供的信息看不出来那行代码引发的报错。
二、解决过程
1、google:
解决问题的第一步往往是先看看“别人咋解决的”:把错误信息ctrl+c ctrl+v到浏览器里google一下先。
stackoverflow里看到的第一个解决方案是通过添加client-only
标签:
<template> <div id="container"> <client-only> <Components> </client-only> <div> </template>
在项目里也照着这个方法在App.vue里添加client-only
标签,重试后发现没有效果,依然报错。
也有说法说是由于标签的关闭写法导致的Hydration errors
。
于是我搜索了下项目代码,发现确实有几处标签是使用类似 <span class="split" />
写法进行关闭的。抱着尝试的心理,我把这些写法都改成了<span class="split"></span>
。
然而重试后依然没有解决这个报错。
2、断点调试:
既然网上的方法没有效果,那只能打断点看看是否能找到报错的具体位置。
从错误报告点击进详情,可以看到是vue.min.js
文件的appendChild抛出的错误。
在这里打一个断点,并运行:
第一次经过此处:e是一个div,t是一个#comment的node节点,此时还没有抛出错误。
第二次经过此处:e是一个div,t是一个text元素,此时还没有抛出错误。
第三次经过此处:e是#comment的node节点,t是一个按钮的div元素,此处抛出了对应的错误。
也就是在第三次运行appendChild时,由于e此时是一个node节点,不支持appendChild方法,于是vue抛出了Uncaught DOMException: Failed to execute 'appendChild' on 'Node': This node type does not support this method.
错误。
在项目里搜索comment,发现并没有找到相应的代码。于是从第三次appendChild的t参数入手。
可以看出来这是一个按钮元素,并且按钮文字内容是“我知道了”。在项目里搜索“我知道了”,可以找到两处符合条件的元素。根据此时的页面位置可以排除captcha组件,所以锁定了verifyResult组件里的“我知道了”按钮。
这处按钮的html代码如下:
<q-button v-if="resultInfo.showBtn" type="primary" @click="resultInfo.callback" > {{ resultInfo.btnText }} </q-button>
先把这部分内容直接注释掉看看。 发现这个报错确实不见了。可以确认,这个按钮就是报错的源头。
3、定位:
那这个按钮到底有啥问题呢?看起来就是一个平平无奇的确认按钮呀。
从刚刚打断点的时候可以看到,此时按钮的text正常取到了"我知道了"文案,且报错信息是在进行appendChild
,也就是添加元素的动作时。而这个按钮里用到了v-if
,合理怀疑是这个v-if
引起的。于是尝试把v-if去掉或改成一个常量,发现页面也不会报错。
所以可以确定,这里的报错是由于v-if的参数引起的。
这里v-if的参数是:resultInfo.showBtn
这里resultInfo是一个计算参数:
showBtn是通过另一个计算参数:isMobile来控制的。
看来问题就在isMobile
上。
通过打印isMobile发现,在node时由于没有window,所以isMobile=false,而页面渲染时isMobile=true。
所以这里isMobile有一个从false -> true的变化。
所以这里按钮元素经历了从无到有的过程,在appendChild的时候node节点就抛出了错误。
4、解决
这里解决方案的主要就是去掉这个从无到有的过程,或者把这个变化后移。
- 去掉这个从无到有的过程:把
v-if
改成v-show
。 - 把这个变化后移:isMobile不使用计算参数,在默认初始化为false,在created时再进行赋值。
created() { this.isMobile = browser.isMobile(); }
两种方法都可以解决,我这里使用了第一种解决方案,报错不再出现,且页面按钮可以正常显示~
加载全部内容