Javascript:添加“选择”表行的能力,使用参数调用事件侦听器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15572082/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 01:13:03  来源:igfitidea点击:

Javascript: Adding ability to "select" rows of a table, calling an event listener with arguments

javascript

提问by dpitch40

I am just starting off teaching myself Javascript after learning some basics in a university class a year ago. For a web app I am supposed to write, I need to allow users to "select" rows of a table, preferably by clicking on them. I have a strong Python background and my approach probably reeks of GTK paradigms. I have a nagging fear that I'm "reinventing the wheel" somehow by trying to do this when there is a much more standard or accepted way, but like I said, don't know much Javascript yet. My Javascript code to try and do this is:

一年前在大学课堂上学习了一些基础知识后,我才开始自学 Javascript。对于我应该编写的网络应用程序,我需要允许用户“选择”表格的行,最好是通过单击它们。我有很强的 Python 背景,我的方法可能散发着 GTK 范式的气息。当有更标准或可接受的方式时,我一直担心我会以某种方式“重新发明轮子”,尝试这样做,但就像我说的那样,还不太了解 Javascript。我尝试执行此操作的 Javascript 代码是:

//Get list of rows in the table
var table = document.getElementById("toppings");
var rows = table.getElementsByTagName("tr");

var selectedRow;

//Row callback; reset the previously selected row and select the new one
function SelectRow(row) {
    if (selectedRow !== undefined) {
        selectedRow.style.background = "#d8da3d";
    }
    selectedRow = row;
    selectedRow.style.background = "white";
}

//Attach this callback to all rows
for (var i = 0; i < rows.length; i++) {
    var idx = i;
    rows[idx].addEventListener("click", function(){SelectRow(rows[idx])});
}

This apparently doesn't work because after the loop exits idx is equal to rows.length - 1 so the row argument in SelectRow is rows[rows.length - 1], which is always the last row; that is, the values of i are not "saved" as arguments to the event listener callback.How can I call an event listener with its own saved arguments? This threadseems to give a way to do this with the onclick property, but I understand that this is deprecated and addEventListener (or some monstrous IE-compatible addEvent library) is now the "correct" way to do it.

这显然不起作用,因为在循环退出后 idx 等于 rows.length - 1 所以 SelectRow 中的行参数是行 [rows.length - 1],它总是最后一行;也就是说,i 的值不会“保存”为事件侦听器回调的参数。如何使用自己保存的参数调用事件侦听器?该线程似乎提供了一种使用 onclick 属性执行此操作的方法,但我知道这已被弃用,并且 addEventListener(或某些与 IE 兼容的可怕的 addEvent 库)现在是执行此操作的“正确”方法。

采纳答案by Ian

You are having a closure problem. Here's a reference: JavaScript closure inside loops – simple practical example

您遇到了关闭问题。这是一个参考:循环内的 JavaScript 闭包——简单实用的例子

Try this:

试试这个:

for (var i = 0; i < rows.length; i++) {
    (function (idx) {
        rows[idx].addEventListener("click", function() {
            SelectRow(rows[idx]);
        });
    })(i);
}

http://jsfiddle.net/2Vs5w/2/

http://jsfiddle.net/2Vs5w/2/

Of course, you don't actually need to pass rows[idx]to SelectRow- you could pass thisand not have to deal with creating a closure to capture the value of iat that time. So something like this:

当然,您实际上并不需要传递rows[idx]SelectRow- 您可以传递this并且不必处理创建闭包来捕获当时的值i。所以像这样:

for (var i = 0; i < rows.length; i++) {
    rows[idx].addEventListener("click", function() {
        SelectRow(this);
    });
}

http://jsfiddle.net/2Vs5w/3/

http://jsfiddle.net/2Vs5w/3/

In the examples, I included a function for effectively attaching an event to an element:

在示例中,我包含了一个有效地将事件附加到元素的函数:

function addEvent(element, evt, callback) {
    if (element.addEventListener) {
        element.addEventListener(evt, callback, false);
    } else if (element.attachEvent) {
        element.attachEvent("on" + evt, callback);
    } else {
        element["on" + evt] = callback;
    }
}

Tries to use the modern standard addEventListener, then attempts to use IE's way - attachEvent, then the DOM0 way - element.onevent. There are several places to get this function from, and probably even better versions, but this should work for now :)

尝试使用现代标准addEventListener,然后尝试使用 IE 的方式 - attachEvent,然后是 DOM0 方式 - element.onevent。有几个地方可以获得这个功能,甚至可能有更好的版本,但这现在应该有效:)

回答by Diego

You have found the usual JavaScript gotcha! :)

您已经找到了常见的 JavaScript 问题!:)

  1. Variables have function scope
  2. Closures maintains a reference to the parent scope (not a copy of variable values).
  1. 变量具有函数作用域
  2. 闭包维护对父作用域的引用(不是变量值的副本)。

If you sum up 1 + 2 you'll figure out why this line is wrong:

如果你总结 1 + 2 你就会明白为什么这条线是错误的:

   rows[idx].addEventListener("click", function(){SelectRow(rows[idx])});

The idxin the closure is a reference to the parent scope (2), at the end of the loop idx = rows.lengthwhy? It doesn't matter that you put the varinside the loop, declarations are at function level (1).

idx在封闭是与母体范围(2)的参考,在循环结束时idx = rows.length为什么呢?var将循环放入循环内并不重要,声明位于函数级别 (1)。

You can use @Ian solution to copy idx.

您可以使用@Ian 解决方案来复制 idx。

NOTE 1:Events handlers receives an event object, you can use event.targetto get the object that fired the event, in that way you don't need to pass row[idx]:

注意 1:事件处理程序接收一个事件对象,您可以使用它event.target来获取触发事件的对象,这样您就不需要传递row[idx]

   rows[idx].addEventListener("click", function(evt){SelectRow(evt.target)});

NOTE 2:Usually attaching event handlers to each row can be inefficient, try by attaching the event handler to the table instead

注意 2:通常将事件处理程序附加到每一行可能效率低下,请尝试将事件处理程序附加到表中