I’m tring to make a game and i want to use window.requestAnimationFrame() to make roles move, the movement seems to be right at first.
but there is problem that when i re-trigger move()
immediately after triggering pause()
, the movement will be faster and faster, i have code blow, move()
、pause()
and initListener()
are functions about movement
JavaScript
x
99
99
1
type state = "init" | "mount" | "moving" | "pause" | "end";
2
3
interface position {
4
left: number;
5
top: number;
6
}
7
8
interface elProps {
9
id: string;
10
text: string;
11
avatar: string;
12
}
13
14
export default class Bullet {
15
public el: HTMLElement;
16
public targetEl: HTMLElement;
17
public unit: string = "px";
18
private id:string;
19
private state: state;
20
private position: position;
21
private animationId: number | undefined;
22
constructor(props: elProps) {
23
if (!props) return;
24
this.el = document.createElement("div");
25
26
this.initEl(props);
27
}
28
initEl(props: elProps) {
29
const defaultStyle = {};
30
this.el.style["height"] = "40px";
31
this.el.style["background"] = "lightblue";
32
this.el.style["display"] = "inline-flex";
33
this.el.style["position"] = "absolute";
34
//
35
const { text, avatar, id } = props;
36
this.el.setAttribute("id", id);
37
this.id = id
38
const textEl = document.createElement("div");
39
textEl.innerText = text;
40
const avatarEl = document.createElement("img");
41
avatarEl.setAttribute("src", avatar);
42
//
43
this.el.appendChild(avatarEl);
44
this.el.appendChild(textEl);
45
//
46
this.state = "init";
47
}
48
mount(targetEl: HTMLElement, position: position, unit: string) {
49
//
50
this.position = position;
51
this.unit = unit;
52
this.targetEl = targetEl;
53
this.el.style["left"] = this.position.left + this.unit;
54
//
55
targetEl.appendChild(this.el);
56
//
57
this.state = "mount";
58
const domEl = document.querySelector(`#${SPECIAL_ID}`);
59
if (!domEl) {
60
throw new Error("mount bullet error");
61
}
62
this.el = domEl as HTMLElement;
63
}
64
move(duration: number) {
65
this.state = "moving";
66
this.initListener();
67
68
const animation = () => {
69
if (this.state !== "moving") return;
70
71
this.position.left -= 1.2;
72
this.el.style["left"] = this.position.left + this.unit;
73
this.animationId = requestAnimationFrame(animation);
74
};
75
animation();
76
}
77
pause() {
78
if(this.animationId){
79
cancelAnimationFrame(this.animationId)
80
this.animationId = undefined
81
}
82
}
83
initListener() {
84
this.el.addEventListener("mouseenter", () => {
85
this.state = "pause";
86
this.pause()
87
});
88
this.el.addEventListener("mouseover", () => {
89
this.state = "pause";
90
this.pause()
91
});
92
this.el.addEventListener("mouseout", () => {
93
this.state = "moving";
94
this.move()
95
});
96
}
97
}
98
99
I guess it’s because when i re-trigger move()
, there are still some requestAnimationFrame()
running in javascript stack?
how can I fix this?
Advertisement
Answer
You should either unregister your event listeners when doing a pause – or register them outside of the move()
function (e.g. in mount()
)