VUEJS項目實踐七之Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of

問題描述:
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);
      }
    }

然後問題就解決啦~只要找到根本原因解決起來就非常快啦

當然這個問題在我這邊的代碼是這樣解決的,其他的場景可能解決起來並不一樣。我只是介紹一下我解決問題的思路啦。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章