javascript - 使用 replaceWith() 方法通过 ID 和变量定位

标签 javascript jquery

所以我的 jquery 代码是这样工作的:当单击其中一个默认图标并加载图像时,它会替换被单击的默认图标。 (有 2 个带有隐藏文件输入的默认图标)。我能够通过以默认图标的父级类名 .border 为目标来实现此功能,但出于某种原因,我无法通过父级的 ID 名称 + [整数变量] - #bd1#bd2。您能否帮助我让我的代码正常工作,以便我能够通过 ID 名称 + [整数变量] 进行定位?

最佳答案

在 jsfiddle 中运行你的代码,看起来这里有两个不同的问题:

问题 #1:事件传播

您的点击事件存在事件冒泡问题(与您的 jquery 选择器无关)。

当您点击父级 .border 时,它会触发对子级 .imginp 的点击。当您触发对子元素的点击时,将再次触发父元素上的事件监听器。这会创建一个无限循环,其中父级上的点击事件监听器会触发对子级的点击,而子级会触发父级点击事件监听器等...这会导致 RangeError: Maximum call stack size exceeded

这是否也是您在控制台中看到的行为?

发生这种情况是因为 event bubbling in 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。我们可以使用 closure 修复此问题将使我们能够将 a 的值“关闭”为循环中函数声明时的值。这是一个很好的例子,说明如何将闭包与 async functions defined in for loops 一起使用。

ES6 为如何防止这个问题提供了另一种选择。关键字 let 使我们能够对变量进行 block 级范围界定。这意味着,我们可以在我们的 for 循环中使用它来为每个循环定义 a,并在循环中定义 block 级范围和 change 回调。你会像这样使用它:

for (let a = 1; a < 3; a++) {...}

这还有一个额外的好处,就是可以修复当前编写 for 循环的方式:使用 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);
        };
      });
    });
}

关于javascript - 使用 replaceWith() 方法通过 ID 和变量定位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57244186/

相关文章:

javascript - 我想使用 ChartJs 的多个数据工具提示

javascript - Django AJAX 登录表单验证

javascript - 如何为用户调整大小的 div?

javascript - 访问json不起作用

jquery - 通过包含文本来选择选项

javascript - 如何在特定的 URL 中启动 Node.js?

jquery - 在 ReactJS 中将表导出为 xls 表

javascript - 从 ASP.NET Gridview 显示 jquery 弹出详细信息页面的最简单方法

javascript - 将 fabricjs Canvas 转换为 base64 图像

javascript - 动态迭代 json 数组并添加到另一个数组