2012-12-20 17 views
1

我在尽我所能学习不显眼的JavaScript。下面的代码试图改变我在HTML标记中调用的getArrays函数的现有实践。这是我能工作的唯一版本。尽管它很好,但我觉得可能会有一些不必要的部分,并且不完全理解为什么我需要最后一行代码(对于addEventListener来说,这是一种新的东西)。我正在使用Mozilla DOM参考示例,并知道如何在jQuery中执行此操作。谢谢!JavaScript单击事件 - 为什么我需要两个addEventListeners?

的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> 

回答

5

如果你正确地构造你的HTML/JS,你不会这样做。

将脚本标记移动到</body>标记之前的正文的底部,并且不再需要等待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

有一点需要注意:即使对于I帧和图像标记被解析,图像本身可能无法下载完成,所以你将不得不等待。此外,iframe内容也可能尚未加载。但DOMContentLoaded并不等待这些。我只是觉得这很好,值得注意。

+0

虽然这个答案提供了一种OP方法的替代方案,但它并不真正回答问题_为什么我需要'addEventListener'?_当然,在这种情况下,事件监听器没有_real_需要,但它们非常强大,并且在当今世界(动态添加内容的ajax)绝对不可或缺 –

+0

呃,它确实,你只需要在行之间读一点更多。我没有描绘出发生了什么的整个画面,但我暗示了它。另外问题是“为什么我需要两个”,一个合理的答案是“你不”。 – rlemon

+0

Gotcha。这就说得通了。谢谢! –

2

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

我建议你把你的JavaScript代码在一个单独的文件,并使用在head节以下HTML代码:<script type="text/javascript" src="yourfilepath.js"></script>。然后,您也可以使用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代码看起来更整洁,更有条理。

+0

'window.onload'确实导致IE浏览器,虽然内存泄漏,而'addEventListener'和'removeEventListener' [可以解决这个问题](http://stackoverflow.com/questions/11186750/memory-leak-risk-in-javascript-closures)相对容易 –

+0

谢谢,这让我对事情更加清楚。 –

2

事件监听器是至关重要到JS。每次用户与您的页面进行交互时,您都需要提取该事件​​并对其进行响应。
当然,在这个片段中,你的函数假定在DOM中有一个给定ID的元素,就绪,设置和等待。这可能不是这种情况,这就是为什么你必须等到JS收到OK(DOMReady事件)。

这只是一个,很简单,为什么可以使用addEventListener的例子。但是,当你开始使用Ajax调用向你的页面添加新内容到你的页面时,国际海事组织(IMO),事件监听器真的会进入他们自己的行列:
假设DOM已准备就绪,但是稍后可能会或可能不会请求某些元素取决于用户输入)。在jQuery中,你会使用这样的事情:

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

这并不需要FOO元素可用这段代码运行时,但一旦元素被添加到DOM中,点击事件将按照您的愿望处理。
在非jQ中,您将使用addEventListener。由于事件模型(见怪异模式对传播和冒泡的细节),听者不必连接到直接的元素:

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异步,而不必检查每个阿贾克斯调用的每个响应...

让我们更进一步甚至:代表团。如您所见,在上面的代码段中,我们正在侦听所有单击事件发生在机构内的某处。这几乎没有区别:所有点击,所以你不需要为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. 单个事件侦听器,处理全部事件为全部元素使您的代码更高效,有时通过提高性能here's a nice example of when delegation is in order,可悲的是,它也表明,X浏览器的发展带来党的痛苦...
相关问题