【问题标题】:JavaScript Click Events - Why do I need two addEventListeners?JavaScript 点击事件 - 为什么我需要两个 addEventListener?
【发布时间】:2012-12-21 04:49:40
【问题描述】:

我正在尽最大努力学习不显眼的 JavaScript。下面的代码尝试更改我使用从 HTML 标记中调用的 getArrays 函数的现有练习片段。这是我可以开始工作的唯一版本。虽然它很好用,但我觉得可能有一些不必要的部分,并且不完全理解为什么我需要最后一行代码(addEventListener 的东西有点新)。我正在研究 Mozilla DOM 参考示例,并且已经知道如何在 jQuery 中执行此操作。谢谢!

JavaScript:

        <script>

        function getArrays() {
            var ddlValArray = new Array();
            var ddlTextArray = new Array();
            var ddl = document.getElementById("ddlFlavors");

            for (i=0; i<ddl.options.length; i++) {
                ddlValArray[i] = ddl.options[i].value;
                ddlTextArray[i] = ddl.options[i].text;
                alert(ddlValArray[i] + ' ' + ddlTextArray[i]);  
            }
        }

        function showArrays() {
            var link = document.getElementById("clickHandler");
            link.addEventListener("click", getArrays, false);   
        }

        document.addEventListener("DOMContentLoaded", showArrays, false);


    </script>

HTML

Select Flavor: 
<select id='ddlFlavors'>
<option value="1">Vanilla</option>
<option value="2">Chocolate</option>
<option value="3">Strawberry</option>
<option value="4">Neopolitan</option>
</select>

<br/><br/>
<a id="clickHandler" href="#">Show Flavors</a>

【问题讨论】:

    标签: javascript click addeventlistener


    【解决方案1】:

    如果你的 HTML / JS 结构正确,你就不会。

    将脚本标签移动到正文底部&lt;/body&gt; 标签之前,您不再需要等待 DOMContentLoaded 事件。它上面的 html 将在 JS 执行之前被解析。

    这可能会导致其他警告,但对于您的示例,它会起作用。

    <body>
    Select Flavor:
    <select id='ddlFlavors'>
        <option value="1">Vanilla</option>
        <option value="2">Chocolate</option>
        <option value="3">Strawberry</option>
        <option value="4">Neopolitan</option>
    </select>
    <br/><br/>
    <a id="clickHandler" href="#">Show Flavors</a>
    <script>
            function getArrays() {
                var ddlValArray = new Array();
                var ddlTextArray = new Array();
                var ddl = document.getElementById("ddlFlavors");
                for (i=0; i<ddl.options.length; i++) {
                    ddlValArray[i] = ddl.options[i].value;
                    ddlTextArray[i] = ddl.options[i].text;
                    alert(ddlValArray[i] + ' ' + ddlTextArray[i]);  
                }
            }
            function showArrays() {
                var link = document.getElementById("clickHandler");
                link.addEventListener("click", getArrays, false);   
            }
            showArrays();
        </script>
    </body>
    

    将脚本放在底部还有许多其他好处。 Read more about them here

    需要注意的一点:即使 iframe 和图像的标签被解析,图像本身也可能没有完成下载,因此您必须等待。 iframe 内容也可能尚未加载。但是 DOMContentLoaded 也不等待这些。我只是觉得很高兴注意到。

    【讨论】:

    • 虽然这个答案提供了 OP 使用的方法的替代方案,但它并没有真正回答问题我为什么需要addEventListener 当然,在这种情况下,没有真正需要事件监听器,但是它们非常强大,在当今世界(ajax动态添加内容)绝对不可或缺
    • 嗯,确实如此,您只需要在字里行间多读一点。我没有描绘出正在发生的事情的全貌,但我提到了它。还有一个问题是“我为什么需要两个”,一个合理的答案是“你不需要”。
    • 明白了。那讲得通。谢谢!
    【解决方案2】:

    事件监听器对 JS 来说是关键。每次用户与您的页面交互时,您都需要了解该事件并做出响应。
    当然,在这个 sn-p 中,您的函数假设 DOM 中有一个具有给定 id 的元素,准备好、设置和等待。情况可能并非如此,这就是为什么您必须等到 JS 收到 OK(DOMReady 事件)。

    这只是一个非常简单的示例,说明为什么可以使用addEventListener。但是 IMO,当您开始使用 Ajax 调用向您的页面添加新内容时,事件侦听器真正发挥了作用:
    假设 DOM 已准备就绪,但稍后可能会或可能不会请求某些元素(取决于用户输入)。在 jQuery 中,你会使用这样的东西:

    $('#foo').on('click',functionRef);
    

    这并不要求在运行此代码时 foo 元素可用,但只要将元素添加到 dom 中,就会按您的意愿处理点击事件。
    在非 jQ 中,您将为此使用 addEventListener。由于事件模型(有关传播和冒泡的详细信息,请参阅 quirksmode),侦听器不需要直接附加到元素:

    document.body.addEventListener('click',function(e)
    {
        if ((e.target || e.srcElemet).id === 'foo')
        {
            //function that deals with clicks on foo element
        }
    },false);//last param is for bubbling/propagating events
    

    这样,您可以为可能异步添加到 dom 的元素绑定所有事件,而无需检查每个 ajax 调用的每个响应...

    让我们更进一步:代表团。如您所见,在上面的 sn-p 中,我们正在侦听 allbody 内部某处发生的点击事件。这几乎没有区别:所有点击,因此您无需为 101 个元素添加 101 个不同的点击侦听器,只需添加一个即可。您唯一需要做的就是编写处理程序以相应地处理每个元素:

    document.body.addEventListener('click',function(e)
    {
        e = e || window.event;
        var elem = e.target || e.srcElement;
        switch (true)
        {
            case elem.id === 'foo':
                //either code here or:
                return fooCallback.apply(elem,[e]);//use another function as though it were the handler
            case elem.id.className.match(/\bsomeClass\b/):
                return someClassCallback.apply(elem,[e]);//~= jQuery's $('.someClass').on('click',function);
             case elem.type === 'text':
                 //and so on
        }
    },false);
    

    相当强大的东西。当然,它还有很多,也有缺点(主要是 X 浏览器的东西),但主要优点是:

    1. 处理动态添加/删除元素的事件
    2. 处理all 元素的all 事件的单个事件侦听器使您的代码更高效,有时会提高性能很多here's a nice example of when delegation is in order,可悲的是,它也显示了X-browser开发给聚会带来的痛苦……

    【讨论】:

      【解决方案3】:

      这行代码:document.addEventListener("DOMContentLoaded", showArrays, false); 确保您的函数 showArrays() 在 DOM 准备好之前不会开始执行。换句话说,函数showArrays() 将在 (X)HTML 文档被加载和解析后开始执行。

      我建议您将 JavaScript 代码放在一个单独的文件中,并在 head 部分中使用以下 HTML 代码:&lt;script type="text/javascript" src="yourfilepath.js"&gt;&lt;/script&gt;。然后你也可以使用window.onloadonclick 事件来代替document.addEventListener() 方法。

      当您这样做时,您可以将代码放在 showArrays 函数的主体之外并删除该函数。

      例如:

      window.onload = function()
      {
        var link = document.getElementById("clickHandler");
        link.onclick = getArrays;
      }
      

      这被认为是一种更好的做法。

      完整示例

      script.js 文件中:

      //This is the beginning of the script...
      
          function getArrays() {
              var ddlValArray = new Array();
              var ddlTextArray = new Array();
              var ddl = document.getElementById("ddlFlavors");
      
              for (i=0; i<ddl.options.length; i++) {
                  ddlValArray[i] = ddl.options[i].value;
                  ddlTextArray[i] = ddl.options[i].text;
                  alert(ddlValArray[i] + ' ' + ddlTextArray[i]);  
              }
          }
      
      window.onload = function()
      {
        var link = document.getElementById("clickHandler");
        link.onclick = getArrays;
      }
      

      在您的 HTML 头中:

      <script type="text/javascript" src="script.js"></script>
      

      在大多数情况下,最好将 JavaScript 与 HTML 文件分开编写,就像 CSS 一样。这样一来,您的 HTML 代码就会看起来更整洁、更有条理。

      【讨论】:

      • window.onload 确实会导致 IE 内存泄漏,而 addEventListenerremoveEventListener can solve this 相对容易
      猜你喜欢
      • 1970-01-01
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 2020-10-04
      • 2015-07-02
      • 1970-01-01
      相关资源
      最近更新 更多