0

我试图在准备好的回调中为元素的所有子 div 设置 onmouseenter 函数。所以身体的负荷是

    function ready(){
      for(var i=0;i<document.getElementById("pieces").childNodes.length;i++){
    var n=document.getElementById("pieces").childNodes.item(i);
    n.onmouseenter=function(){showBorder(n);};
    n.onmouseleave=hideBorder;
     }
    }

但是所有获得其 onmouseenter 函数的 div 都使用在循环结束时出现的 n 值。我希望每个 onmouseenter 在设置回调时使用 n 的值。

我能做些什么?提前致谢

4

2 回答 2

1

问题是处理程序绑定到相同的 single n。因此,更改会n更改所有处理程序。n

您可以做的是n通过传递n给在每次迭代中执行的即时函数来“本地化”。这使得n每个处理程序都绑定到n立即函数的,而不是n函数的ready

function ready() {
    var n;
    for (var i = 0; i < document.getElementById("pieces").childNodes.length; i++) {

        //the local n takes precedence over the outer n
        //therefore any use of n in the immediate function refers to the local n
        (function(n) {

            //you can actually name the variable anything you want
            //but to override the outer n, we use n for our local n

            n = document.getElementById("pieces").childNodes.item(i);
            n.onmouseenter = function() {
                showBorder(n);
            };
            n.onmouseleave = hideBorder;
        }(n));
    }
}​
于 2012-06-28T03:49:09.230 回答
0

JavaScript 具有函数级作用域,因此循环中的变量声明n(但不是document.getElementById('pieces').childNodes.item(i)to的赋值nfor实际上被提升到ready函数的顶部。

要理解这一点,假设您的代码实际上是这样编写的,因为 JavaScript 引擎实际上是这样解释它的:

function ready() {
    var i, n;
    for (i = 0; i < document.getElementById('pieces').childNodes.length; i++) {
        n = document.getElementById("pieces").childNodes.item(i);
        n.onmouseenter = function () { showBorder(n); };
        n.onmouseleave = hideBorder;
    }
}

The assignment of function () { showBorder(n); } to n's onmouseenter property creates a closure such that when that anonymous function actually executes it will have access to any and all data that was in scope at the time of creation, i.e. when the ready function is invoked. Thus, every one of those onmouseenter methods will have a reference to the variable n which, by the time ready's execution is complete, has a value equivalent to document.getElementById('pieces').childNodes.length.

I would suggest the following code snippet:

function ready() {
    var pieces, i, l, n;
    pieces = document.getElementById('pieces').childNodes;
    for (i = 0, l = pieces.length; i < l; i++) {
        n = pieces.item(i);
        n.addEventListener('mouseover', (function (m) {
            showBorder(m);
        })(n), false);
        n.addEventListener('mouseout', hideBorder, false);
    }
}
  1. Declare all variables at the top of the scope so there's no confusion about their scope within the function context.
  2. Lookup document.getElementById('pieces').childNodes once and assign that memory location to the pieces variable to avoid another lookup every time you need to reference that set of nodes.
  3. The comparison statement in the for loop is executed every iteration so instead of looking up pieces.length repeatedly assign it to the variable l once and reference that variable each time instead.
  4. The use of on<event> methods of a DOM element is, for the most part, the worst way to assign event handlers if for nothing else because you can only have a single function registered to a given DOM element at any time. The addEventListener method is the preferable way to assign handlers unless you expect your users to have an older version of Internet Explorer which instead uses the attachEvent method.
  5. The mouseenter and mouseleave events were not standard DOM events but rather custom events added by Microsoft for older versions of Internet Explorer. They were added to the DOM Level 3 specification and Firefox and Opera introduced support for these events, but Webkit still does not support them.
于 2012-06-28T04:47:01.530 回答