問題描述:
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);
}
}
然後問題就解決啦~只要找到根本原因解決起來就非常快啦
當然這個問題在我這邊的代碼是這樣解決的,其他的場景可能解決起來並不一樣。我只是介紹一下我解決問題的思路啦。