2010-01-23 133 views
3

oK,所以我有一對夫婦,最終可能會出現這個論壇過於新手的問題,關於不引人注意的事件處理。事件處理問題(Javascript)

據我瞭解,正確建立文件將是這個樣子:

<html> 
<head> 
<title>Title</title> 
<script src="jsfile.js" type="text/javascript></script> 
</head> 
<body> 

//Body content, like some form elements in my case 

</body> 
</html> 

Jsfile.js會是這個樣子:

function a() { 
//code; 
} 
function b()... 

window.addEventListener('load', a, false); 
document.getElementById("id").addEventListener('click', b, false); 
document.myForm.typeSel.addEventListener('change', c, false); 

//or to use better browser-compatible code... 

function addEvent(obj,evt,fn) { 
if (obj.addEventListener) 
    obj.addEventListener(evt,fn,false); 
else if (obj.attachEvent) 
    obj.attachEvent('on'+evt,fn); 
} 
addEvent(window, 'load', a); 
addEvent(document.getElementById('id'), 'click', b); 
addEvent(document.myForm.typeSel, 'change', c); 

據我瞭解,同時,在瀏覽器的頭部加載這個javascript代碼,將每個事件處理程序添加到它們各自的元素中。但是...雖然窗口處理程序正確添加,其他人都沒有。但是,如果將放置在函數內,則訪問元素的(例如)getElementById方法工作得很好,並添加事件處理程序。所以我可以想象,通過window onload調用一個loadEvents()函數,該函數包含我需要事件處理程序的其他文檔元素的所有addEvent()函數。但據我瞭解,我不應該這樣做。

另外,如果我是粘在身體內的addEvent代碼與它解決的元素,如沿...

<input type="checkbox" id="test" /> 
<script type="text/javascript> 
document.getElementById("test").onclick = func; 
</script> 

...然後正常工作。但它當然也違反了刪除內聯事件處理程序的全部原因!

所以問題的存在:爲了使用 「元素閱讀進度( '咔噠',FUNC,FALSE)」, 「的addEvent(元素, '點擊',FUNC)」,甚至是「元素 .onclick = func「 - 我怎樣才能成功地引用一個頭文件尾部的元素,而不必將它粘在的另一個函數中?爲什麼getElementById和其他類似的方法不能在頭部的函數之外工作?

或者,我的底層理解是否存在一些缺陷?

回答

2

<script>置於<head>曾經是智慧。但是現在,有了繁重的ajax頁面,<script>越來越多,但在體內,儘可能低於下面。這個想法是加載和解析<script>保持頁面的其餘部分不被加載,因此用戶將看到一個空白頁面。通過確保身體儘可能快地被加載,您可以讓用戶看到一些東西。請參閱YAHOO最佳實踐以獲得有關此問題的最佳解釋:http://developer.yahoo.com/performance/rules.html

現在,不管那個問題,現在設置它的代碼都無法工作 - 至少,不是當您嘗試附加處理程序尚未創建。例如,在這一行:

document.getElementById("id").addEventListener('click', b, false); 

你會得到一個運行時錯誤如果與id="id"的元素是體內。現在,如果你把<script>放在下面的內容中,在內容之後(包括id="id"的內容,它就會起作用,因爲腳本是在這些元素的html代碼被解析並添加到DOM之後執行的。

如果您確實希望將腳本放在首位,那麼您可以這樣做,但您需要將事件處理程序的添加與頁面內容的呈現同步。您可以通過將它們全部添加到文檔或窗口裝入處理程序中來完成此操作。所以,如果你會寫:

//cross browser add event handler 
function addEventHandler(obj,evt,fn) { 
    if (obj.addEventListener) { 
     obj.addEventListener(evt,fn,false); 
    } else if (obj.attachEvent) { 
     obj.attachEvent('on'+evt,fn); 
    } 
} 
addEventHandler(document, 'load', function(){ 
    //set up all handlers after loading the document 
    addEventHandler(document.getElementById('id'), 'click', b); 
    addEventHandler(document.myForm.typeSel, 'change', c); 
}); 

它確實有效。

+0

非常感謝。我有點kick然心動,沒有想到這一點。我甚至在我的addEvent()函數中發出警報,以查明通過參數發送了什麼對象,並發現它是「未定義的」。我應該從邏輯上理解它。好吧。 此外,感謝鏈接到雅虎頁面 - 我一直在尋找方法,以確保我編碼達到最高標準,如更新到不顯眼的JavaScript ......我之所以有這個麻煩的全部原因第一名! – David 2010-01-23 05:26:04

+0

沒有必要踢自己:)對我來說,編程總是邏輯思維和試錯之間的混合物。我認爲對大多數人來說就是這樣,否則我們不會有這麼多的軟件測試框架。至於編碼達到最高標準......我不知道,知道你在做什麼以及爲什麼要這樣做肯定是件好事。但是,一個POV的高標準可能會被另一個人所詬病。 – 2010-01-23 12:51:09

0

您是否熟悉jQuery
它的一個JavaScript庫,具有一些非常棒的工具。
例如,如果您希望在頁面之後完成一些js操作(如果完全加載並創建了所有DOM元素(以避免那些煩人的例外),則可以簡單地使用ready()方法。
我也看到你想附加click \ change事件jQuery照顧這也:)你不必擔心所有這些跨瀏覽器問題。
看看jQuery selectors可以讓你的生活更輕鬆,當試圖獲取一個元素。

這就是它,只是給它一個鏡頭,它有一個非常直觀的API和一個很好的文檔。

+0

感謝您的提示,我一定會檢查出來。 – David 2010-01-23 05:14:13

1

window.addEventListener工作的原因document.getEle...().addEventListener並不簡單:window當您執行該代碼時存在對象,而id="abc"的元素仍未加載。

當您的瀏覽器下載頁面的源代碼時,會盡快解析並執行源代碼。因此,如果您將script放置在head元素中(在源的最開始處),它會在某些<div id="abc">...</div>甚至被下載之前執行。 所以我覺得現在你知道爲什麼

<div id="test">Blah</div> 
<script type="text/javascript">document.getElementById("test").style.color = "red";</script> 

的作品,而這一點:

<script type="text/javascript">document.getElementById("test").style.color = "red";</script> 
<div id="test">Blah</div> 

沒有。

您可以通過多種方式處理該問題。最流行的是:

  • 在文件末尾把腳本(右前</body>
  • 使用事件推遲執行腳本

第一種方式應該明確的權利,但個人我更喜歡最後一個(即使情況更糟)。

那麼如何處理事件呢?當瀏覽器最終下載並解析整個源碼時,執行DOMContentLoaded事件。此事件意味着源代碼已準備就緒,您可以使用JavaScript來操作DOM。

window.addEventListener("DOMContentLoaded", function() { 
    //here you can safely use document.getElementById("...") etc. 
}, false); 

可惜不是每一個瀏覽器支持DOMContentLoaded事件,但一如既往...... Google is the anwser。但這不是壞消息的結束。正如你注意到的,addEventListener沒有得到IE的支持。那麼...這個瀏覽器真的讓人生活困難,你將不得不破解一件事... Yes... once again - Google。但它是IE,所以不是全部。普通的瀏覽器(如Opera或Firefox)支持W3C Event Model,而IE支持its own--所以再次 - Google提供跨瀏覽器解決方案。

addEventListener可能現在似乎是附加事件的最糟糕的方式,但事實上它是最好的。它允許您輕鬆添加或刪除單個元素上的單個事件的許多偵聽器。

PS。我注意到您考慮使用Load事件來執行您的腳本。不要這樣做。 Load事件執行得太晚。您必須等到每個圖像或文件加載完畢。您應該使用DOMContentLoaded事件。 ;)

編輯: 我忘記了...處理跨瀏覽器事件模型是非常容易,當你使用一些框架,如非常流行的jQuery。但瞭解瀏覽器的工作原理是很好的。