问题描述:
Failed to execute ‘removeChild’ on ‘Node’: The node to be removed is not a child of this node.
问题背景:
在我之前的博文
VUEJS项目实践五之Dialog弹出框MessageBox(超好看的bootstrap样式)
中有介绍一个样式结合了Bootstrap样式的MesageBox
然后在之前的博文
VUEJS项目实践四之自定义键盘指令(按键即获取焦点)
中介绍了一种按键自动获取焦点,并触发事件的方法。
现在在MessageBox绑定按键Enter的时候,发现报错
messageBox.vue?cb02:80 Uncaught DOMException: Failed to execute ‘removeChild’ on ‘Node’: The node to be removed is not a child of this node.
首先贴一下Message.vue文件
<template>
<div v-key-bind-listen>
<div class="msgBox" v-show="isShowMessageBox">
<div class="msgBox_header">
<div class="msgBox_title">
<h3>{{ title }}</h3>
</div>
</div>
<div class="msgBox_content">
<p>{{ content }}</p>
</div>
<div class="msgBox_btns">
<button type="button" class="btn btn-lime btn-lg" id="confirmBtn" @click="confirm" bind_key="ENTER">确定</button>
<button type="button" class="btn btn-dark btn-lg" id="cancelBtn" @click="cancel" bind_key="ESC">取消</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'messageBox',
data(){
return {
title: '',
content: '',
isShowMessageBox: false,
resolve: '',
reject: '',
promise: '' // 保存promise对象
}
},
methods: {
close(state){
this.model.show = false;
if(this.model.callback){
this.model.callback(state);
}
},
// 确定,将promise断定为resolve状态
confirm: function () {
this.isShowMessageBox = false;
this.resolve('confirm');
this.remove();
},
// 取消,将promise断定为reject状态
cancel: function () {
this.isShowMessageBox = false;
this.reject('cancel');
this.remove();
},
// 弹出messageBox,并创建promise对象
showMsgBox: function () {
this.isShowMessageBox = true;
this.promise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
// 返回promise对象
return this.promise;
},
remove: function () {
setTimeout(() => {
this.destroy();
}, 300);
},
destroy: function () {
this.$destroy();
document.body.removeChild(this.$el);
}
}
}
</script>
<style scoped>
.msgBox {
position: fixed;
z-index: 4;
left: 50%;
top: 35%;
transform: translateX(-50%);
width: 420px;
background-color: black;
opacity: 0.55;
}
.msgBox_header {
padding: 20px 20px 0;
}
.msgBox_title {
padding-left: 0;
margin-bottom: 0;
font-size: 26px;
font-weight: 800;
height: 18px;
color: #fff;
}
.msgBox_content {
padding: 30px 20px;
color: #fff;
font-size: 18px;
font-weight: 200;
}
.msgBox_btns {
padding: 10px 20px 15px;
text-align: right;
overflow: hidden;
}
@keyframes show-messageBox {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes bounce-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>
这里定义的v-key-bind-listen指令就是按键监听用的,具体怎么写的可以参考之前的博客,再写一遍就没意思了。
VUEJS项目实践四之自定义键盘指令(按键即获取焦点)
按ESC取消的时候没有问题
按ENTER键确认的时候就会报上面的错
messageBox.vue?cb02:80 Uncaught DOMException: Failed to execute ‘removeChild’ on ‘Node’: The node to be removed is not a child of this node.
通过控制台定位到错误。
这个报错翻译过来就是,删了一个node,但是它不是body的子Node。
在destroy方法里加一行日志,控制台打印this.$el看看,发现出现两次。
console.log(this.$el)
再加一行日志,判断一下this.$el到底是不是body的子Node
console.log(document.body.contains(this.$el))
通过控制台可以发现,这个destroy方法执行了两遍,第一遍this.$el是body的子节点,第二遍就不是了。
所以把上面的destroy方法改一下就可以了
destroy: function () {
this.$destroy();
if (document.body.contains(this.$el)) {
document.body.removeChild(this.$el);
}
}
然后问题就解决啦~只要找到根本原因解决起来就非常快啦
当然这个问题在我这边的代码是这样解决的,其他的场景可能解决起来并不一样。我只是介绍一下我解决问题的思路啦。