因此,我的jQuery代码工作如下:当单击默认图标并加载图像时,它替换了单击的默认图标。(有2个默认图标,带有隐藏的文件输入(。我能够通过针对默认图标的class名称.border
来实现此功能,但是由于某种原因,我无法用父级的ID名称 [整数变量] -#bd1
或#bd2
来定位。您能帮我让我的代码工作,以便我能够按ID名称 [整数变量]定位?
在JSFiddle中运行代码,看来这里有两个单独的问题:
问题#1:事件传播
您的点击事件有一个事件冒泡的问题(与您的jQuery选择器无关(。
单击父 .border
时,它会触发一个单击孩子.imginp
。当您触发单击子元素时,再次触发了父级的事件侦听器。这会创建一个无限的循环,在该循环中,单击事件侦听器在父母上触发一个单击的孩子,该孩子触发父母点击事件侦听器等...这会导致RangeError: Maximum call stack size exceeded
。
这是您在控制台中也看到的行为吗?
这是由于JavaScript中的事件冒泡而发生的。首先,单击.imginp
是由该元素处理的,然后由其父母处理,然后由祖父母等,依此类推,直到到达window
元素为止。这意味着,即使目标是.imginp
元素,也会在.border
元素上点击。这就是将代码变为循环状态的原因。
您可以通过在孩子上添加听众来将事件的传播停止给父母:
:$('#inp'+a).click(function (e) {
e.stopPropagation();
});
问题2:变量范围
这与您的jQuery选择器有关。具体来说,您使用循环变量a
和执行change
事件回调的选择器使用。
这里发生的事情的快速示例。
for (var i = 0; i < 3; i++){
setTimeout(function() {
console.log(i)
}, 100)
}
乍一看看到此代码时,您可能希望它可以记录0, 1,2
。相反,它将记录3,3,3
。这是因为到超时函数运行时,a
的值为3。
这正是代码$('#bd'+a).replaceWith(template);
中此行的情况。如果您在此处添加console.log
,则可以在行动中看到此行为。在执行时,这里的a
的值不是1或2,而是3。这是因为它使用了a
的最新值,而不是定义函数时a
的值。
这与JavaScript中事件循环的行为有关。当执行change
回调并评估#bd + a
时,a
的值是3。我们可以使用闭合来解决此问题,该封闭使我们能够在 a
的值中"关闭"函数声明时的 CC_24值。循环。这是一个很好的示例,说明如何与循环中定义的异步函数一起使用闭合。
es6提供了如何防止此问题的另一种选择。关键字let
使我们能够对变量具有块级别范围。这意味着,我们可以在循环中使用它来定义每个循环的a
,并在其中定义的块级别范围范围范围范围范围范围范围范围。您会这样使用:
for (let a = 1; a < 3; a++) {...}
这具有额外的好处,还可以修复当前编写的循环方式:以a
作为全局变量。这通常是不可取的,如果您在代码中其他地方定义或使用可变的a
,可能会产生意外的后果。
最终代码:
for (let a = 1; a < 3; a++) {
$("#bd"+a).click(function(e) {
$(this).children(".imginp").click()
});
$('#inp'+a).click(function (e) {
e.stopPropagation();
});
$('#inp'+a).on('change', function(e){
var files = e.target.files;
$.each(files, function(i, file){
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(e){
template =
'<div class="border">'+
'<input id="inp'+a+'" class="imginp" type="file" hidden>'+
'<img class="blah" src="'+e.target.result+'">'+
'</div>';
$('#bd'+a).replaceWith(template);
};
});
});
}