精华内容
下载资源
问答
  •  web,我们常常需要为某一类型元素添加事件,这时,常用for循环。对于刚刚接触不久小白总是容易这里犯错,比如我。因此今天这里记录一下自己踩过坑,希望对大家有所帮助。  假如我们需要为页面上...

    一 、问题的出现

              在web中,我们常常需要为某一类型的元素添加事件,这时,常用for循环。对于刚刚接触不久的小白总是容易在这里犯错,比如我。因此今天在这里记录一下自己的踩过的坑,希望对大家有所帮助。

             假如我们需要为页面上的一组按钮添加点击事件。采用for循环,最容易写成如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
        <button class="btn">btn0</button>
        <button class="btn">btn1</button>
        <button class="btn">btn2</button>
        <button class="btn">btn3</button>
        <button class="btn">btn4</button>
        <button class="btn">btn5</button>
    </body>
    <script src="//code.jquery.com/jquery-1.12.4.js"></script>
    <script>
        var btnArray = document.getElementsByClassName('btn');
        for (var i = 0; i < btnArray.length; i++) {
             btnArray[i].onclick = function () {
                  alert(i);
             };
        }
    </script>
    </html>

    此时点击每个按钮,并不是显示对应的按钮上的数字0、1、2……而是点击任何一个按钮时,显示的都是6。


    二、一般解决方案

    这个是为什么呢?

    我们都知道JS中,内层函数是可以访问外层函数中的值的,并且可以直接调用。但是JS的函数是调用时触发。在每次的循环中onclick的函数体并没有执行。当点击按钮时,触发了onclick函数,这时再执行函数体中的内容。但是,此时循环已经结束。i的值已经在最后依次循环中变为了5+1=6。所以,所有按钮的点击事件触发时,i的值都是6。

         那这个时候能采用什么办法来解决这个问题呢?

         其中比较简单的一种方法就是为将循环写在一个闭包中。JS代码如下:

    var btnArray = document.getElementsByClassName('btn');
    for (var i = 0; i < btnArray.length; i++) {
         btnArray[i].onclick = (function close(j) {
             return function () {
                 alert(j);
             }
         })(i);
    }

    其中close就是一个闭包函数,你也可以省去函数名,作为一个匿名函数。这个闭包函数在声明后就立刻执行,这样这个函数的作用域里面就保存了i的值。函数的返回结果是事件处理函数,其中的参数j是close里面保存的j值,也就是循环时传入的值。这样再点击按钮时,出现的效果就是我们预想的效果。

    当然,这里还有其他利用外部函数来解决这个问题的办法。比如,在将事件绑定的函数写在一个外围函数中:

    var btnArray = document.getElementsByClassName('btn');
    for (var i = 0; i < btnArray.length; i++) {
        attach(i,btnArray[i]);
    }
    function attach(ii,o) {
        o.onclick = function () {
            alert(ii);
        }
    }

    attach函数可以写在for循环之内。

    类似的更多解决方案可以参考下面这篇博文:

    http://www.cnblogs.com/liaopr/p/3928802.html


    三、事件委托解决问题

          采用这种方式解决上述问题,需要理解什么是事件委托。

          我们应该找到事件绑定就是将一个事件与一个dom元素绑定在一起,当对dom元素进行操作时,就会触发绑定的事件。而事件委托是将事件绑定到我们原本想要绑定的元素的父元素,委托父类元素来根据触发条件触发相应的事件。打个比方,就相当于我们生活中的取快递。事件绑定相当于我们的快递到时,要自己去快递小哥那里取。事件委托就是快递先到我们小区管理人员那里。管理人员根据快递的收件人来通知需要取快递的那个人去取快递。快递就相当于事件,我们是子元素,管理人员是父类元素。

      为什么可以这样用呢?这时因为浏览器处理dom事件的过程为:一、事件捕获 二、事件目标阶段  三、事件起泡阶段 。

      事件捕获:当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素的节点流去,直到到达事件真正发生的目标元素。这个过程中,事件相应的监听函数是不会被触发的。

      事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。

      事件起泡:从目标元素开始,往顶层元素传播。途中如果有节点绑定了相应的事件处理函数,这些函数都会被一次触发。如果想阻止事件起泡,可以使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)来组织事件的冒泡传播。

            可以看出在事件起泡阶段时,事件流是不断向目标元素之上的节点推动的。目标元素的父类元素和祖先元素的事件处理函数都会执行。所以,我们在需要绑定事件的元素的父类元素绑定事件,在元素触发事件时,父类元素的事件监听会被执行,再根据事件监听内的相应条件,对子元素进行操作。

    所以,我们这之前的问题可以这么解决(父类元素选取的是document):

    document.onclick = function(event){
        //IE doesn't pass in the event object
        event = event || window.event;
        //IE uses srcElement as the target
        var target = event.target || event.srcElement;
        target.onclick = function () {
            alert(target.innerHTML.substr(3));
        }
    };

    这个是使用原生JS写。还可以使用JQuery提供的delegate函数:

    delegate() 方法为指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序,并规定当这些事件发生时运行的函数。

    使用 delegate() 方法的事件处理程序适用于当前或未来的元素(比如由脚本创建的新元素)可参见W3CShool:

    http://www.w3school.com.cn/jquery/event_delegate.asp

    $(selector).delegate(childSelector,event,data,function)

     selector: 需要添加事件的元素的父类元素(必填)

    childSelector:需要添加事件的元素(必填)

    even:事件类型(必填)

    data:传递到函数的额外参数(选填)

    function:事件发生时需要执行的函数。

    代码如下:
    $(document).delegate('button','click',function () {
        alert($(this).html().substr(3));   //$(this)访问添加事件的元素
    })


    四、使用事件委托的好处

     在需要频繁创建和删除dom元素或创建大量的dom元素时,并为这些动态生成的元素添加事件时,建议使用事件委托。这时因为,这时使用事件绑定将存在较大的事件和内存上的开销。此外,使用事件绑定时,不能为新添加的元素绑定相应的事件。即,我们在事件绑定的函数之后添加了新的元素,新元素上没有相应的事件。测试代码如下:

    var btnArray = document.getElementsByClassName('btn');
        for (var i = 0; i < btnArray.length; i++) {
            btnArray[i].onclick = (function close(j) {
                return function () {
                    alert(j);
                }
            })(i);
        }
        var btn = document.createElement('button');
        $(btn).html('hi');
        $(btn).insertAfter('button')

    html中后台添加的‘hi'的按钮是没有绑定click的事件的。

    但是如果使用事件委托,则新添加的元素也是绑定了click事件的。如下代码:

    $(document).delegate('button','click',function () {
        alert($(this).html());   //$(this)访问添加事件的元素
    });
    
    var btn = document.createElement('button');
    $(btn).html('hi');
    $(btn).insertAfter('button')

    关于更多事件委托的介绍可以参考如下三篇博客(介绍更为详细):
         http://www.diguage.com/archives/71.html

    http://www.uml.org.cn/AJAX/201610905.asp

    https://juejin.im/entry/57ea329e67f3560057ad41a6


    展开全文
  • ![图片说明](https://img-ask.csdn.net/upload/202008/18/1597765375_19614.png)![图片说明]... 第一份代码控制台输出一个1 第二份代码控制台输出四个1 ...爸爸救救我
  • 本来想着直接通过js代码来点击事件时让div宽度变化然后写了如下代码 但是无论如何点击都一下子显示完全部宽度; 然后网上通过很久查找网上资料改成如下: 就能够显示出我想要效果了; 纵观这样...

    本来想着直接通过js代码来点击事件时让div的宽度变化然后写了如下的代码

    但是无论如何点击都一下子显示完全部的宽度;

    然后网上通过很久查找网上的资料改成如下:

    就能够显示出我想要的效果了;

    纵观这样的代码现象,才明白是因为闭包的问题,上图中的变量i直接引用了父函数中的i,所以在循环结束后才将最终的值传给了

    子函数,而下图则只是引用了父函数中的i的值,

    转载于:https://www.cnblogs.com/dongcong/p/6591250.html

    展开全文
  • JS在for循环中绑定事件的失效问题

    千次阅读 2018-08-14 13:30:09
    使用for循环去绑定onclick事件,但js绑定失效. 如下图 var btns = document.getElementsByTagName('input'); for (var i = 0; i &amp;amp;amp;amp;lt; btns.length; i++) {//for循环遍历...

    问题描述

    一个简单的点击案例,我们需要实现通过点击改变按钮的值,
    使用for循环去绑定onclick事件,但js绑定失效.

    如下图
    这里写图片描述

              var btns = document.getElementsByTagName('input');
              for (var i = 0; i < btns.length; i++) {//for循环遍历每一个input对象
                  btns[i].onclick = function () {//为每一个input对象绑定点击事件
                      //将每一个input标签的value值改为girl
                      for (var j = 0; j < btns.length; j++) {
                          btns[j].value = 'girl'
                      }
                      btns[i].value = 'boy'//将当前input标签的value值更改为boy
                  }
              }
    

    但是这样并不能得到我们想要的结果
    浏览器打开后控制台将会报错:

    Uncaught TypeError: Cannot set property ‘value’ of undefined (value未定义)

    那为什么会出现这种情况呢
    我们走一遍流程

    1. for循环为每一个input元素绑定点击事件(仅仅只是绑定,没有执行)
    2. 鼠标点击input元素,元素触发点击事件
     btns[i].onclick = function () {//为每一个input对象绑定点击事件
                      //将每一个input标签的value值改为girl
                      for (var j = 0; j < btns.length; j++) {
                          btns[j].value = 'girl'
                      }
                      btns[i].value = 'boy'//将当前input标签的value值更改为boy
                  }
    但是由于js中仅仅只是绑定了点击事件,并没有执行,
    等点击事件执行时,for循环早已结束,
    所以此时i的值等于btns数组的长度,也就是6
    因此btns[i].value会被认为没有定义.

    所以如果想要解决这种点击时”i”值不能相匹配的问题
    可以使用下面的方法

    1.使用闭包函数.
    点击事件绑定函数相当于一个内嵌函数,
    在点击事件绑定的时候就把相应”i”值保存在函数中.

    for (var i = 0; i < btns.length; i++) {//for循环遍历每一个input对象
    
       (function(i){//自执行匿名函数,将"i"值保存在函数中(闭包函数原理)
    
        btns[i].onclick = function () {//为每一个input对象绑定点击事件
            //将每一个input标签的value值改为girl
    
            for (var j = 0; j < btns.length; j++) {
                btns[j].value = 'girl'
            }
            btns[i].value = 'boy'//将当前input标签的value值更改为boy
        }
    
       })(i)
    
    }

    2.使用this值代替btns[i],直接指代点击事件的当前对象.

    for (var i = 0; i < btns.length; i++) {//for循环遍历每一个input对象
        btns[i].onclick = function () {//为每一个input对象绑定点击事件
            //将每一个input标签的value值改为girl
            for (var j = 0; j < btns.length; j++) {
                btns[j].value = 'girl'
            }
    
            this.value = 'boy'//使用this值指代当前对象
        }
    }

    3.给btns[i]创建一个自定义属性,用来保存”i”值.
    注:这个方法适合只需要在函数内部使用当前对象的”i”值
    如果需要使用当前对象就直接使用this关键字.

    var btns = document.getElementsByTagName('input');
    for (var i = 0; i < btns.length; i++) {//for循环遍历每一个input对象
    
        btns[i].index=i;//使用自定义属性储存"i"值
    
        btns[i].onclick = function () {//为每一个input对象绑定点击事件
            //将每一个input标签的value值改为girl
            for (var j = 0; j < btns.length; j++) {
                btns[j].value = 'girl'
    
            btns[this.index].value = 'boy'//使用自定义属性表示当前对象的"i"值
    
        }
    }
    展开全文
  • 最简单方式就是分开写,一个按钮对应一个点击事件函数,这样虽然通俗易懂,但是这样代码量是十分大,既然我们获得是一个事件数组,为什么不用一个for循环来解决呢,于是就有了下面这一种写法(本代码...

    在学习JS时遇到了一个问题,就是如果有多个按钮时,我们可以通过document.getElementByTagName(“button”)的方式来获取事件数组,在获取后我们需要监听每一个按钮是否被点击。最简单的方式就是分开写,一个按钮对应一个点击事件函数,这样虽然通俗易懂,但是这样的代码量是十分大的,既然我们获得的是一个事件的数组,为什么不用一个for循环来解决呢,于是就有了下面这一种写法(本代码是通过点击按钮实现图片的切换):

    for(var i=0; i<allLi.length; i++){
                var sLi = allLi[i];
                sLi.index = i+1;
                sLi.onclick = function () {
                    box.style.background = 'url("images/0'+ this.index +'big.jpg") no-repeat';
                }
            }

    刚开始看到这个也是一脸懵逼,因为之前一直做的是ACM,对于程序执行过程十分敏感,感觉这不合常理啊,一直不知道他这是怎么执行的,for循环执行完了以后,应该再去点击的时候就没用了啊,但是这里依旧可以,说明在JS中,事件的监听的执行不是按照严格的执行先后顺序来的,而是随时点,随时执行,这种写法只是简化了上面所提到的最直接的书写方式,通过for循环去实现后,其实和把他们展开的写法是一模一样的,但是要确定你点的究竟是哪个按钮,就要通过this来实现。

    另一个就是需要通过改变其背景属性来实现背景的切换,那就是要改名字,名字要更改一个数字,但是我们不能通过i去实现,因为在for循环执行完毕后,i就变成了5,那么就无法去改变了,所以我们可以通过改变它的index属性来实现。

    展开全文
  • JS中for循环绑定事件

    2020-11-10 11:21:36
    网页有五个按钮,需求为:点击按钮,将按钮索引值输出。 初学JS时遇到问题,今天学习bind方法时又想起来了,分享一下。 先看一下代码 var btns = document.querySelectorAll('button') for (var i = 0; i ...
  • ![![图片说明](https://img-ask.csdn.net/upload/201811/09/1541749603_855968.png)图片说明]... 感觉没啥错,我看跟老师也一样,只不懂为啥aLi是undefined
  • for(var i = 0;i;i++) { arry[i] = new createjs.Shape(); step_x = Math.random()*(300-50)+50; step_y = 70*(i+1); arry[i].graphics.beginFill("#12fF56").drawRect(step_x, step_y, 100, 20); arr_x_r[i] ...
  • 当异步事件发生时,会创建事件并放入执 行队列,等待当前代码执行完成之后再执行这些代码,如鼠标点击事件发生、定时器触发事件发生、XMLHttpRequest完成回调这些事件,都会被放 入执行队列等待。 关于Js的阻塞
  • 刚开始遇到一个问题就是我HTML写了四个标签,想给每个li 绑定一个点击事件,通过点击每个li ,弹出它对应索引,刚开始是这么做: 无标题文档 window.onload=function(){ var li=document.getElementsByTagN
  • 在js中,如果用for循环进行事件绑定,可能会遇到一点小问题,看下面第一个示例,无论点击哪个div,都会弹出3,即length。 因为这相当于事件绑定同时,并没有把所对应i进行一起绑定,i值是最后一个值,即3。 ...
  • 超给力的Js中for循环的阻塞机制

    千次阅读 2019-07-25 12:04:03
    Js阻塞机制,跟Js引擎单线程处理方式有关,每个window一个JS线程。所谓单线程,某个特定时刻...当异步事件发生时,会创建事件并放入执 行队列,等待当前代码执行完成之后再执行这些代码,如鼠标点击事件发...
  • 遇见此问题,代码检查了n...PS这是js的处理方法, jquery直接用each遍历元素绑定点击事件即可避免 $('#id').each(function(i){ $(this).click(function(){  alert(i); }); }); 转自 : https://
  • 其实这个问题解决关系到变量作用域知识点。 我们都知道变量有全局变量和局部变量,在一些强类型语言中,比如Java中,向下面代码,会输出 0~5 ...但是在js中,情况会变得比较复杂 var oLi =document.getEl...
  • 问题描述: 见题目 解决方法: 1.自定义属性 1.1.css自定义属性 1.2. js的自定义属性 2.使用闭包 代码: 这里插入代码片
  • i++)中的i是一个i,这就导致做点击事件的时候,无论谁点击,结果i都是退出循环后最终的i固定不变。其实这个问题C#中压根不是问题........最后查了下,再加上技术群大佬们的指点,终于理解了原因。接下来就举例子给...
  • 制作了一个页面,其中有一些文本标签,希望每点击一次其标签前的数字框中的数字可以增加一,但是具体用的时候一直报错。请教大家为什么会这样以及如何解决?感激不尽! 标签对应的代码如下: ```html ...
  • js中的事件委托

    2021-05-28 20:43:28
    一张图看懂事件委托 ...比如我们有100个li,每个li都有相同click点击事件,可能我们会用for循环的方法,来遍历所有li,然后给它们添加事件,那这么做会存在什么影响呢? JavaScript,添加到页面上
  • 比如我们有1000个li,每个li都有相同click点击事件,可能我们会用for循环的方法,来遍历所有li,然后给它们添加事件,那这么做会存在什么影响呢? JavaScript,添加到页面上事件处理程序数量将直接关系到...
  • 什么是事件委托? ...比如我们有一亿个li,每个li都有相同click点击事件,如果我们会用for循环的方法,来遍历所有li,然后给它们添加事件,那这么做会存在什么影响呢? JavaScript,添加到
  • 什么是事件委托 就是A,B,C要处理同一类型...比如我们有100个li,每个li都有相同click点击事件,可能我们会用for循环的方法,来遍历所有li,然后给它们添加事件,那这么做会存在什么影响呢? JavaScript,添
  • 使用js开发过程,经常会遇到这样一个问题“如何对多个li添加onClick点击事件,并且输出点击对象当前内容”。这是我们就想到了常用的for循环,如下图所示: 直接输出当前点击对象内容 通过运行会发现依次...
  • 在点击"终端控制"时候能够开启多个窗口对多个终端进行管理: /**提交事件**/ $("#terminalControl").bind("click",function(){ $("#terminalControl").removeClass(); $("#terminalControl").addClass...
  • 工作,有时会有这样需求:一个页面上添加了6个按钮,然后分别为他们绑定点击事件监听器,当点击按钮1时,输出1,当点击按钮2时,输出2。 循环绑定代码如下: for (var i = 1, i <= 6; ++i){ var ...
  • 循环是我们常用控制语句,在JS中每次循环结束后其 i 值会指向最后一次结果,这样循环注册事件时使用到 i 值便会出错。 //获取元素,并注册事件,在点击li后,输出当前 i 值 var list = document....
  • JS事件委托

    2020-07-08 21:41:28
    比如我们有100个li,每个li都有相同click点击事件,可能我们会用for循环的方法,来遍历所有li,然后给它们添加事件,那这么做会存在什么影响呢? 操作DOM次数过多,造成浏览器重排和重绘就越多; 每个事件都是...
  • php里面有一个div一直不间断滚动着多张小图,我js文件里要效果是一旦点击其中一个小图就把这个小图放大。 现在我用是一个循环来给这十多个小图设置监听,但是监听无法让程序知道是哪一个小图被点击了:...

空空如也

空空如也

1 2 3 4 5
收藏数 91
精华内容 36
关键字:

在js中for循环中的点击事件