javascript - 未删除事件侦听器 - 点亮元素
问题描述
我正在研究一个有两个视图的发光元素图像组件。
- 用户一次只能看到一个图像的单一视图。
- 用户可以一次查看所有图像的网格视图。
只需按一下按钮,我就可以在两个视图之间切换。当我在“网格视图”中时,我已经设置了一种在您单击图像时选择图像的方法,它将被标记为已选中。
当我加载图像并切换到网格视图时,我可以毫无问题地选择和取消选择图像。如果我单击返回单个视图然后返回网格视图,我无法选择任何图像。如果我第三次这样做,我可以再次选择图像。
通过调试,我发现添加到图像的事件侦听器没有被删除。通过对这个问题的研究,我尝试了几种不同的方法,但没有解决这个问题。
这是我拥有的代码,希望有人能帮上忙
case 'grid':
this.changeViewState(buttonName);
imageItems.forEach((image) => {
image.addEventListener('click', this.selectImage.bind(this,image), false);
});
hiImage.viewMode = 'grid';
break;
selectImage(image){
let hiImage = this._getImageSection().querySelector("hi-images");
hiImage.dispatchEvent(new CustomEvent('selected-images', {
detail: { image: image }
}));
image.removeEventListener('click', this.selectImage.bind(this,image));
}
提前感谢您提供的任何帮助,我可以在 javascript 和 lit element 方面获得新的信息。
更新:这就是我目前拥有的。这是单击以切换到网格视图的按钮
case 'grid':
this.changeViewState(buttonName);
imageItems.forEach((image) => {
const boundFn = this.selectImage.bind(this, image);
this.boundFnsByImage.set(image, boundFn);
image.addEventListener('click', boundFn);
});
hiImage.viewMode = 'grid';
break;
这是我的按钮单击以切换到单个视图这是应该删除事件侦听器的位置。
case 'single':
console.log('gridswitch button was clicked');
this.boundFnsByImage.forEach((boundFn, image) => {
image.removeEventListener('click', boundFn);
});
this.changeViewState(buttonName);
hiImage.viewMode = 'single';
hiImage.dispatchEvent(new CustomEvent('set-nav-icons'));
break;
推送事件调度的 SelectImage 函数
selectImage(image) {
let hiImage = this._getImageSection().querySelector("hi-images");
hiImage.dispatchEvent(new CustomEvent('selected-images', {
detail: { image: image }
}));
console.log('click selected image');
}
以及这部分组件的属性和构造函数
static get properties() {
return {
name: { type: String }, // ID of the button
tooltip: { type: String },// sets a tooltip for the button
icon: { type: String }, // sets the icon of the button
for: { type: String }, // binds label to input control when it is used
confirmationType: { type: Boolean },
boundFnsByImage: { type: WeakMap }
}
}
constructor() {
super();
this.confirmationType = false;
this.boundFnsByImage = new WeakMap();
}
我想要做什么所以当点击gridswitch按钮时,它会从单一视图变为gridview - 我可以在其中选择一个或多个图像。
然后,当单击单视图按钮时,它会切换回单视图,并应从网格视图图像中删除事件侦听器。
所以当我切换回网格视图时,我可以再次选择它们
还在发生什么。事件侦听器被添加到第二次和随后切换到网格视图的图像中,这意味着它不止一次这样做,所以当我点击它时它会触发两次。
没有发生什么事件侦听器没有从图像中删除,因此在切换回网格视图时可以再次正确设置它们。
解决方案
当你.bind
创建一个函数时,你创建了一个全新的函数,它不是===
以前可能存在的任何函数(即使使用相同的过程创建)。所以
this.selectImage.bind(this,image) === this.selectImage.bind(this,image)
将评估为-引用不同函数对象false
的每一侧的表达式。===
因为selectImage
看起来要删除侦听器,所以一种选择是改为使用{ once: true }
以确保侦听器只运行一次:
imageItems.forEach((image) => {
image.addEventListener('click', this.selectImage.bind(this, image), { once: true });
});
另一种方法是将绑定函数存储在某处,以便removeEventListener
稍后使用它调用,例如
const boundFnsByImage = new Map();
// ...
imageItems.forEach((image) => {
const boundFn = this.selectImage.bind(this, image);
boundFnsByImage.set(image, boundFn);
image.addEventListener('click', boundFn);
});
然后用
selectImage(image){
let hiImage = this._getImageSection().querySelector("hi-images");
hiImage.dispatchEvent(new CustomEvent('selected-images', {
detail: { image: image }
}));
const boundFn = boundFnsByImage.get(image); // <----------------------
// if you want to remove the listener when clicked:
image.removeEventListener('click', boundFn);
}
另请注意,除非您想使用捕获,否则无需将第三个useCapture
参数传递给 - 它默认为反正。addEventListener
false
如果您想一次删除所有侦听器(例如在视图切换期间),请遍历 Map:
boundFnsByImage.forEach((boundFn, image) => {
image.removeEventListener('click', boundFn);
});
推荐阅读
- c++ - 有没有办法从 Visual Studio 的控制台窗口中隐藏此消息?
- r - 错误:逻辑索引向量的长度必须为 1
- xml - 使用 xslt 查找重复值并用唯一值替换它们
- c# - 通过jQuery将部分视图调用到Bootstrap Modal?
- grails - 我有最新版本的 grails 3.3.7,但是当我检查 grails -version 时,它仍然显示 2.3.11。另外,我需要升级到 2.5.6。
- python - 在python脚本中获取ifstat值
- xml - 使用 Spark / Scala 从 XML 记录中提取元素
- python - 用两个不同的定界符分割字符串的最佳方法,将两个单词大写,只包含一个定界符,然后重新添加两个定界符?
- jquery - 在 jquery ajax 调用之后,我想重定向到另一个页面并希望在该页面上打印返回的 json 数据
- lyft-api - Lyft Developer API 乘车请求 - 需要额外权限