刺激控制器:多次监听事件;如何删除事件侦听器并保留上下文?
Stimulus controller: event listened multiple times; how do I remove event listeners and retain the Context?
我的 HTML 页面上有以下控制器:
...
<div data-controller="parent">
<div data-target="parent.myDiv">
<div data-controller="child">
<span data-target="child.mySpan"></span>
</div>
</div>
</div>
...
此子控制器映射到以下 child_controller.js
class:
export default class {
static targets = ["mySpan"];
connect() {
document.addEventListener("myEvent", (event) => this.handleMyEvent(event));
}
handleMyEvent(event) {
console.log(event);
this.mySpanTarget; // Manipulate the span. No problem.
}
}
如您所见,Stimulus 控制器的 connect()
上有一个事件侦听器,当它检测到事件被触发时,它会记录事件并操作跨度目标。
当我从 parent_controller.js
:
替换目标 myDiv
的内容时出现问题
...
let childControllerHTML = "<div data-controller="child">...</div>"
myDivTarget.innerHTML= childControllerHTML;
...
现在 myEvent
被触发,事件侦听器选择它不是一次,而是两次(因为同一个事件被记录了两次)。随后每次替换子项 HTML,事件都会比以前多记录一次。
我知道可以利用 document.removeEventListener
来防止旧控制器仍然监听事件:
export default class {
static targets = ["mySpan"];
connect() {
this.myEventListener = document.addEventListener("myEvent", (event) => this.handleMyEvent(event));
}
disconnect() {
document.removeEventListener("myEvent", this.myEventListener);
}
handleMyEvent(event) {
console.log(event);
this.mySpanTarget; // FAILS. Can't find span.
}
}
但是这样做会使 handleMyEvent
方法丢失 context
,因为它不再在 this
.
下找到 mySpanTarget
如何从子控制器中删除侦听器,因为它不再在 DOM 中,所以我无法访问它,同时保留上下文?
我在 StimulusJS's Discourse page 上找到了答案。
初始化控制器时必须使用bind
方法:
export default class {
static targets = ["mySpan"];
initialize() {
this.boundHandleMyEvent = this.handleMyEvent.bind(this);
}
connect() {
document.addEventListener("myEvent", this.boundHandleMyEvent);
}
disconnect() {
document.removeEventListener("myEvent", this.boundHandleMyEvent);
}
handleMyEvent(event) {
console.log(event);
this.mySpanTarget; // Manipulate the span. No problem.
}
...
}
现在,事件只被监听一次,上下文不会在 handleMyEvent
方法中丢失。
我的 HTML 页面上有以下控制器:
...
<div data-controller="parent">
<div data-target="parent.myDiv">
<div data-controller="child">
<span data-target="child.mySpan"></span>
</div>
</div>
</div>
...
此子控制器映射到以下 child_controller.js
class:
export default class {
static targets = ["mySpan"];
connect() {
document.addEventListener("myEvent", (event) => this.handleMyEvent(event));
}
handleMyEvent(event) {
console.log(event);
this.mySpanTarget; // Manipulate the span. No problem.
}
}
如您所见,Stimulus 控制器的 connect()
上有一个事件侦听器,当它检测到事件被触发时,它会记录事件并操作跨度目标。
当我从 parent_controller.js
:
myDiv
的内容时出现问题
...
let childControllerHTML = "<div data-controller="child">...</div>"
myDivTarget.innerHTML= childControllerHTML;
...
现在 myEvent
被触发,事件侦听器选择它不是一次,而是两次(因为同一个事件被记录了两次)。随后每次替换子项 HTML,事件都会比以前多记录一次。
我知道可以利用 document.removeEventListener
来防止旧控制器仍然监听事件:
export default class {
static targets = ["mySpan"];
connect() {
this.myEventListener = document.addEventListener("myEvent", (event) => this.handleMyEvent(event));
}
disconnect() {
document.removeEventListener("myEvent", this.myEventListener);
}
handleMyEvent(event) {
console.log(event);
this.mySpanTarget; // FAILS. Can't find span.
}
}
但是这样做会使 handleMyEvent
方法丢失 context
,因为它不再在 this
.
mySpanTarget
如何从子控制器中删除侦听器,因为它不再在 DOM 中,所以我无法访问它,同时保留上下文?
我在 StimulusJS's Discourse page 上找到了答案。
初始化控制器时必须使用bind
方法:
export default class {
static targets = ["mySpan"];
initialize() {
this.boundHandleMyEvent = this.handleMyEvent.bind(this);
}
connect() {
document.addEventListener("myEvent", this.boundHandleMyEvent);
}
disconnect() {
document.removeEventListener("myEvent", this.boundHandleMyEvent);
}
handleMyEvent(event) {
console.log(event);
this.mySpanTarget; // Manipulate the span. No problem.
}
...
}
现在,事件只被监听一次,上下文不会在 handleMyEvent
方法中丢失。