如何重新启动循环 requestAnimationFrame

how to restart a loop requestAnimationFrame

我想做一个游戏,我想用window.requestAnimationFrame()让角色移动,一开始看起来移动是对的。

但是有问题,当我重新触发 move()触发pause()后,移动会越来越快,我有代码吹,move()pause()initListener()是关于移动的函数

type state = "init" | "mount" | "moving" | "pause" | "end";

interface position {
  left: number;
  top: number;
}

interface elProps {
  id: string;
  text: string;
  avatar: string;
}

export default class Bullet {
  public el: HTMLElement;
  public targetEl: HTMLElement;
  public unit: string = "px";
  private id:string;
  private state: state;
  private position: position;
  private animationId: number | undefined;
  constructor(props: elProps) {
    if (!props) return;
    this.el = document.createElement("div");

    this.initEl(props);
  }
  initEl(props: elProps) {
    const defaultStyle = {};
    this.el.style["height"] = "40px";
    this.el.style["background"] = "lightblue";
    this.el.style["display"] = "inline-flex";
    this.el.style["position"] = "absolute";
    // 
    const { text, avatar, id } = props;
    this.el.setAttribute("id", id);
    this.id = id
    const textEl = document.createElement("div");
    textEl.innerText = text;
    const avatarEl = document.createElement("img");
    avatarEl.setAttribute("src", avatar);
    //
    this.el.appendChild(avatarEl);
    this.el.appendChild(textEl);
    //
    this.state = "init";
  }
  mount(targetEl: HTMLElement, position: position, unit: string) {
    //
    this.position = position;
    this.unit = unit;
    this.targetEl = targetEl;
    this.el.style["left"] = this.position.left + this.unit;
    //
    targetEl.appendChild(this.el);
    //
    this.state = "mount";
    const domEl = document.querySelector(`#${SPECIAL_ID}`);
    if (!domEl) {
      throw new Error("mount bullet error");
    }
    this.el = domEl as HTMLElement;
  }
  move(duration: number) {
    this.state = "moving";
    this.initListener();

    const animation = () => {
      if (this.state !== "moving") return;

      this.position.left -= 1.2;
      this.el.style["left"] = this.position.left + this.unit;
      this.animationId = requestAnimationFrame(animation);
    };
    animation();
  }
  pause() {
    if(this.animationId){
      cancelAnimationFrame(this.animationId)
      this.animationId = undefined
    }
  }
  initListener() {
    this.el.addEventListener("mouseenter", () => {
      this.state = "pause";
      this.pause()
    });
    this.el.addEventListener("mouseover", () => {
      this.state = "pause";
      this.pause()
    });
    this.el.addEventListener("mouseout", () => {
      this.state = "moving";
      this.move()
    });
  }
}

我猜是因为当我重新触发move()时,javascript堆栈中还有一些requestAnimationFrame()运行?

我该如何解决这个问题?

您应该在暂停时取消注册您的事件侦听器 - 或者在 move() 函数之外注册它们(例如在 mount() 中)