Uncaught DOMException: Failed to execute 'removeChild' on 'Node'

写一个贪吃蛇,但是当移动后新创建了蛇身的cell后,后一步的蛇身没办法删除,浏览器总是报错:
"Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node."

    let snake = null;

    class Cell {
      constructor(x, y, classname) {
        this.x = x;
        this.y = y;
        this.cell = document.createElement('div');
        this.classname = classname
      }
     
      add() {
        this.cell.style.position = 'absolute';
        this.cell.style.width = CELL + 'px';
        this.cell.style.height = CELL + 'px';
        this.cell.style.left = this.x * CELL + 'px';
        this.cell.style.top = this.y * CELL + 'px';
        this.cell.className = this.classname || '';
        MAP.appendChild(this.cell);
      }
     
      remove() {
        MAP.removeChild(this.cell);
      }
    }

    class Snake {
      constructor() {
        this.head = null; //蛇头
        this.headPos = [];
        this.tail = null; //蛇尾
        this.pos = []; //身体位置 二维数组
        this.direction = null; //行走方向
      }
      
      init() {
        //create snake head
        let _x = random(SNAKE_LEN - 1, MAP_WIDTH - SNAKE_LEN); //随机生成坐标
        let _y = random(SNAKE_LEN - 1, MAP_WIDTH - SNAKE_LEN);
        let head = new Cell(_x, _y, 'snakehead');
        head.add();
        this.head = head;
        this.pos.push([_x, _y]);

        this.direction = ...;
        
        //蛇身
        let nxt = null, pre = this.head;
        for (let i = 1; i < SNAKE_LEN; i++) {
          let body = new Cell(_x - i * this.direction.x, _y - i * this.direction.y, 'snakebody');
          body.add();
          this.head.nxt = i === 1 ? body : null; //链表
          body.nxt = nxt;
          body.pre = pre;
          pre = body;
          this.pos.push([_x - i * this.direction.x, _y - i * this.direction.y]);
          //保存蛇尾
          this.tail = i === SNAKE_LEN - 1 ? body : null;
        }
      }
      
      //判断蛇头前一格位置
      check() {
        let gameover = false;
        // console.log(this.head)
        let nextPos = [this.head.x + this.direction.x, this.head.y + this.direction
          .y
        ]; // [蛇头当前坐标this.head + 1*方向系数] //nextpos[0]-x nextpos[1]-y
        
        //移动
        this.move(nextPos);
      }

      //判断后的行动
      move(nextPos, getFood) {
        //创建一个新身体在原来蛇头的位置
        let newBody = new Cell(this.head.x, this.head.y, 'snakebody');
        newBody.nxt = this.head.nxt;
        this.head.remove();
        newBody.add();
        //在蛇头下一个位置创建一个新蛇头
        let newHead = new Cell(nextPos[0], nextPos[1], 'snakehead');
        newHead.add();
        newBody.pre = newHead;
        this.head = newHead; //更新蛇头
        newHead.nxt = newBody;
        this.pos.unshift(nextPos); //更新this.pos
        //移除旧蛇尾
        if (!getFood) { //没食物, this.tail变前面一个, 删除tail
          console.log('remove tail');
          this.tail.remove();
          this.tail = this.tail.pre;
          this.pos.pop();
        }
      }
    }
    
    //游戏本身 构造函数
    class Game {
      constructor() {
        this.score = null;
        this.timer = null;
        this.level = 0;
      }

      init() {
        //地图
        MAP.style.width = MAP_WIDTH * CELL + 'px';
        MAP.style.height = MAP_WIDTH * CELL + 'px';
        map(MAP_WIDTH);
        //画蛇
        snake = new Snake();
        snake.init();
        //开始移动
        this.start();
      }

      start() {
        this.timer = setInterval(() => {
          snake.check();
          // snake.check();
        }, 1000);
      }
    }

    let game = new Game;
    game.init();

一开始的时候蛇都移动都没问题,每次当蛇尾移动到move()里创建的格子时,浏览器就开始报错,并且无法删除该位置;

可我也不知道哪里错了,求指导!

阅读 7.1k
2 个回答

链表里面的原来的body第一位cell.pre应该指向newBody
let newBody = new Cell(...)下面添加
this.head.nxt.pre = newBody;

可以把 remove 代码段放在 setTimeout 回调函数里

推荐问题