调用 removeEventListener 后滚动事件仍然有效
Scroll event still working after removeEventListener was called
我正在使用 lit-element,有些地方需要添加滚动侦听器和 运行 一些函数,因此决定为此创建一个 'service',它将添加 EventListener 和可以将函数作为回调。在调用 unsubscribeDomEvents()
时,它应该 removeEventListener。
所以基本功能正常,但 removeEventListener 无效。即使在 unsubscribeDomEvents()
被调用之后,我仍然可以从 _onScroll()
看到这个控制台。这是我现在拥有的:
const SCROLL_DOWN = 'scrollDown';
export class ScrollManager {
private container: HTMLElement;
private _callbacks = [];
private readonly _scrollBind;
constructor({ container }) {
this._scrollBind = this._onScroll.bind(this);
this.container = container;
this.container.addEventListener('scroll', this._scrollBind);
}
onScrollDown(callback): ScrollManager {
return this._registerCallback(SCROLL_DOWN, callback);
}
unsubscribeDomEvents(): void {
this.container.removeEventListener('scroll', this._scrollBind);
}
private _registerCallback(callbackType: string, callback): ScrollManager {
this._callbacks[callbackType] = callback;
return this;
}
private _isScrollToBottom(container: HTMLElement): boolean {
return container.scrollHeight - container.scrollTop - container.clientHeight < 1;
}
private _onScroll(): void {
console.log('onscroll');
if (this._isScrollToBottom(this.container)) {
this._callbacks[SCROLL_DOWN]();
}
}
}
这是我在组件中使用它的方式
stateChanged(state: IState): void {
...
this.isEditMode = state.modes.isEditMode;
if (this.isEditMode) {
this._scrollManager = new ScrollManager({ container: this.container })
.onScrollDown(this.onScrollDown.bind(this));
} else {
this._scrollManager?.unsubscribeDomEvents();
}
this.requestUpdate();
}
private onScrollDown(): void {
// some function
}
如有任何帮助,将不胜感激!
致未来的 Google 员工
您在这里正确地避免了一个常见错误:
this._scrollBind = this._onScroll.bind(this);
在保留对原始绑定函数的引用并取消订阅的地方:
this.container.removeEventListener('scroll', this._scrollBind);
否则您将尝试取消订阅另一个功能
你的情况
观察你的 stateChanged
函数,如果它触发不止一次而 isEditMode
是真实的,那么你将实例化 ScrollManager
两次,但取消订阅一次。
我认为这是正确的形式:
stateChanged(state: IState): void {
...
this.isEditMode = state.modes.isEditMode;
this._scrollManager?.unsubscribeDomEvents();
if (this.isEditMode) {
this._scrollManager = new ScrollManager({ container: this._scrolableContainer })
.onScrollDown(this.onScrollDown.bind(this));
}
this.requestUpdate();
}
我正在使用 lit-element,有些地方需要添加滚动侦听器和 运行 一些函数,因此决定为此创建一个 'service',它将添加 EventListener 和可以将函数作为回调。在调用 unsubscribeDomEvents()
时,它应该 removeEventListener。
所以基本功能正常,但 removeEventListener 无效。即使在 unsubscribeDomEvents()
被调用之后,我仍然可以从 _onScroll()
看到这个控制台。这是我现在拥有的:
const SCROLL_DOWN = 'scrollDown';
export class ScrollManager {
private container: HTMLElement;
private _callbacks = [];
private readonly _scrollBind;
constructor({ container }) {
this._scrollBind = this._onScroll.bind(this);
this.container = container;
this.container.addEventListener('scroll', this._scrollBind);
}
onScrollDown(callback): ScrollManager {
return this._registerCallback(SCROLL_DOWN, callback);
}
unsubscribeDomEvents(): void {
this.container.removeEventListener('scroll', this._scrollBind);
}
private _registerCallback(callbackType: string, callback): ScrollManager {
this._callbacks[callbackType] = callback;
return this;
}
private _isScrollToBottom(container: HTMLElement): boolean {
return container.scrollHeight - container.scrollTop - container.clientHeight < 1;
}
private _onScroll(): void {
console.log('onscroll');
if (this._isScrollToBottom(this.container)) {
this._callbacks[SCROLL_DOWN]();
}
}
}
这是我在组件中使用它的方式
stateChanged(state: IState): void {
...
this.isEditMode = state.modes.isEditMode;
if (this.isEditMode) {
this._scrollManager = new ScrollManager({ container: this.container })
.onScrollDown(this.onScrollDown.bind(this));
} else {
this._scrollManager?.unsubscribeDomEvents();
}
this.requestUpdate();
}
private onScrollDown(): void {
// some function
}
如有任何帮助,将不胜感激!
致未来的 Google 员工
您在这里正确地避免了一个常见错误:
this._scrollBind = this._onScroll.bind(this);
在保留对原始绑定函数的引用并取消订阅的地方:
this.container.removeEventListener('scroll', this._scrollBind);
否则您将尝试取消订阅另一个功能
你的情况
观察你的 stateChanged
函数,如果它触发不止一次而 isEditMode
是真实的,那么你将实例化 ScrollManager
两次,但取消订阅一次。
我认为这是正确的形式:
stateChanged(state: IState): void {
...
this.isEditMode = state.modes.isEditMode;
this._scrollManager?.unsubscribeDomEvents();
if (this.isEditMode) {
this._scrollManager = new ScrollManager({ container: this._scrolableContainer })
.onScrollDown(this.onScrollDown.bind(this));
}
this.requestUpdate();
}