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);
      }
    }

然后问题就解决啦~只要找到根本原因解决起来就非常快啦

当然这个问题在我这边的代码是这样解决的,其他的场景可能解决起来并不一样。我只是介绍一下我解决问题的思路啦。

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