Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 在线免费中文字幕,国产日韩在线播放,亚洲激情99

          整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          一文告訴你Vue的事件處理

          一文告訴你Vue的事件處理

          ue 事件處理

          • 使用 v-on 指令 (簡寫為 @) 來監(jiān)聽 DOM 事件,并在事件觸發(fā)時執(zhí)行對應(yīng)的 JavaScript。
          • methods 承載多是事件函數(shù)
          • v-on 可以用 @替換

          用法

          v-on:click="methodName" 
          

          @click="methodName"
          

          事件處理器的值可以是:

          內(nèi)聯(lián)事件處理器:事件被觸發(fā)時執(zhí)行的內(nèi)聯(lián) JavaScript 語句 (與 onclick 類似)。

          方法事件處理器:一個指向組件上定義的方法的屬性名或是路徑。

          按鈕點(diǎn)擊操作

          場景一

          按鈕點(diǎn)擊對應(yīng)前端控制臺輸出文本:

          js<script>
          export default{
            name: 'app',
            data(){
            },
            methods:{
              clickHandle(){
                console.log("Hello 點(diǎn)擊事件");
              }
            }
          
          }
          </script>
          <template>
            <main>
              <div>
                <h1>事件處理</h1> 
                <button v-on:click="clickHandle">按鈕</button>
                <button  @click="clickHandle">按鈕</button>
              </div>
          
            </main>
          </template>
          
          • 點(diǎn)擊三次,前端頁面控制臺輸出打印三次:Hello 點(diǎn)擊事件

          場景二

          按鈕點(diǎn)擊,文本交替顯示或消失

          js<script>
          export default{
            name: 'app',
            data(){
            },
            methods:{
              clickHandle(){
                console.log("Hello 點(diǎn)擊事件");
              },
              clickText(){
                this.flag=!this.flag;
              }
            }
          
          }
          </script>
          <template>
            <main>
              <div>
                <h1>事件處理</h1> 
                <button v-on:click="clickHandle">按鈕</button>
                <p v-if="flag">文本按鈕顯示</p>
                <button @click="clickText">文本按鈕</button>
              </div>
            </main>
          </template>
          

          再次點(diǎn)擊一次,按鈕上文本消失。

          在事件中改變文本是否顯示的屬性值,methods編寫對應(yīng)方法,索引到data屬性內(nèi)定義的值。

          注意:所有data里面的屬性都是通過this來索引修改

          列表文本事件處理

          場景一

          js<script>
          export default{
            name: 'app',
            data(){
            },
            methods:{
              listHandle(e){
                console.log(e);
              }
            }
          }
          </script>
          <template>
            <main>
              <div>
                <h1>事件處理</h1> 
                <button v-on:click="clickHandle">按鈕</button>
                <p v-if="flag">文本按鈕顯示</p>
                <button v-on:click="clickText">文本按鈕</button>
                <ul>
                  <li @click="listHandle"  
                    v-for="(value, key, index) in bookObj" :key="index" >
                    {{index+1}}. {{key}} : {{value}}
                  </li>
                </ul>
              </div>
            </main>
          </template>
          
          • 傳入?yún)?shù)e,對應(yīng)前端頁面控制臺輸出元素點(diǎn)擊操作屬性內(nèi)容

          場景二

          對應(yīng)文本傳入事件進(jìn)行處理

          <script>
          export default{
            name: 'app',
            data(){
            },
            methods:{
              clickHandle(){
                console.log("Hello 點(diǎn)擊事件");
              },
              clickText(){
                this.flag=!this.flag;
              },
              listHandle(value){
                console.log(value);
              }
            }
          
          }
          </script>
          <template>
          <main>
              <div>
                <h1>事件處理</h1> 
                <ul>
                  <li @click="listHandle(value)"  
                    v-for="(value, key, index) in bookObj" :key="index" >
                    {{index+1}}. {{key}} : {{value}}
                  </li>
                </ul>
              </div>
            </main>
          </template>
          
          • value代表方法傳入的文本信息,不代表envent對象

          即想傳遞參數(shù)又想傳遞envent對象

          js    listHandle(value,e){
                console.log(value,e);
              }
          

          事件修飾符

          修飾符是用 . 表示的指令后綴,包含以下這些:

          • .stop
          • .prevent:事件將不再重新加載頁面
          • .self
          • .capture
          • .once
          • .passive

          頁面不跳轉(zhuǎn)

          • 點(diǎn)擊a標(biāo)簽,對應(yīng)頁面跳轉(zhuǎn)失效

          過統(tǒng)計數(shù)據(jù)庫中的1000多個項目,我們發(fā)現(xiàn)在 JavaScript 中最常出現(xiàn)的錯誤有10個。下面會向大家介紹這些錯誤發(fā)生的原因以及如何防止。

          對于這些錯誤發(fā)生的次數(shù),我們是通過收集的數(shù)據(jù)統(tǒng)計得出的。Rollbar 會收集每個項目中的所有錯誤,并總結(jié)每個錯誤發(fā)生的次數(shù),然后通過各個錯誤的特征進(jìn)行分組。

          下圖是發(fā)生次數(shù)最多的10大 JavaScript 錯誤:

          下面開始深入探討每個錯誤發(fā)生的情況,以便確定導(dǎo)致錯誤發(fā)生的原因以及如何避免。

          1. Uncaught TypeError: Cannot Read Property

          這是 JavaScript 開發(fā)人員最常遇到的錯誤。當(dāng)你讀取一個屬性或調(diào)用一個未定義對象的方法時,Chrome 中就會報出這樣的錯誤。

          導(dǎo)致這個錯誤發(fā)生的原因有很多,常見的一種情況是在渲染 UI 組件時,不正確地初始化狀態(tài)。我們來看一個真實(shí)的應(yīng)用程序中發(fā)生這種情況的例子。

          以上代碼有兩個重要方面:

          1. 一是組件的狀態(tài)(例如 this.state),在開始生命周期之前是 undefined 狀態(tài)。

          2. 二是當(dāng)通過異步的方式獲取數(shù)據(jù)時,無論是在構(gòu)造函數(shù)中 componentWillMount 中,還是在構(gòu)造函數(shù)中提取 componentDidMount,組件在數(shù)據(jù)加載之前至少會渲染一次。當(dāng)檢測首次渲染時,會發(fā)現(xiàn) this.state.items 是未定義的。此時就會出現(xiàn)一個錯誤 -“Uncaught TypeError: Cannot read property ‘map’ of undefined" in the consol”。

          解決的方法很簡單:在構(gòu)造函數(shù)中使用合理的默認(rèn)值進(jìn)行狀態(tài)初始化。

          2. TypeError: ‘undefined’ Is Not an Object (evaluating...)

          這是在 Safari 中讀取屬性或調(diào)用未定義對象上的方法時發(fā)生的錯誤,這與 Chrome 的上述錯誤基本相同,只是 Safari 使用不同的錯誤消息。

          3. TypeError: Null Is Not an Object (evaluating...)

          這是在 Safari 中讀取屬性或調(diào)用空對象上的方法時發(fā)生的錯誤。

          有趣的是,在 JavaScript 中,null 和 undefined 是兩種不同的類型,這就是為什么會出現(xiàn)兩個不同的錯誤消息。未定義通常是一個尚未分配的變量,而 null 則表示該值為空。要驗證它們不相等,請使用嚴(yán)格的相等運(yùn)算符:

          在實(shí)際情況中,導(dǎo)致這種錯誤的原因之一是:在元素加載之前,就嘗試在 JavaScript 中使用 DOM 元素。這是因為 DOM API 對于空白的對象引用返回 null。

          任何執(zhí)行和處理 DOM 元素的 JS 代碼,都應(yīng)該在創(chuàng)建 DOM 元素之后執(zhí)行。JS 代碼按照 HTML 中的規(guī)定自上而下進(jìn)行解釋。因此,如果在 DOM 元素之前存在標(biāo)簽,則腳本標(biāo)簽內(nèi)的 JS 代碼就會在瀏覽器分析 HTML 頁面時執(zhí)行。如果在加載腳本之前尚未創(chuàng)建 DOM 元素,就會出現(xiàn)這樣的錯誤。

          在這個例子中,我們可以通過添加一個事件偵聽器來解決這個問題,事件偵聽器會在頁面準(zhǔn)備就緒時通知我們。一旦 addEventListener 被觸發(fā),該 init( ) 方法就可以使用 DOM 元素。

          4. (unknown): Script Error

          當(dāng)未捕獲的 JavaScript 錯誤違背跨邊界原則時,就會發(fā)生腳本錯誤。例如,如果將 JavaScript 代碼托管在 CDN 上,則任何未被捕獲的錯誤(通過 window.onerror 處理程序發(fā)出的錯誤,而不是 try-catch 中捕獲到的錯誤)將僅報告為“腳本錯誤”。這是瀏覽器的一種安全措施,主要用于防止跨域傳遞數(shù)據(jù)的情況出現(xiàn)。

          要獲取真實(shí)的錯誤消息,需要執(zhí)行以下操作:

          Access-Control-Allow-Origin

          將 Access-Control-Allow-Origin 設(shè)置為 *, 表示可以從任何域正確訪問資源。* 如有必要,也可以用自己的域名進(jìn)行替換,例如:

          Access-Control-Allow-Origin: www.example.com。

          以下是在各種環(huán)境中設(shè)置的一些示例:

          • Apache

          在 JavaScript 文件夾中,創(chuàng)建一個 .htaccess 文件,并包含以下內(nèi)容:

          • Nginx

          將 add_header 指令添加到提供 JavaScript 文件的 location block 中:

          • HAProxy

          將以下內(nèi)容添加到提供 JavaScript 文件的靜態(tài)資源配置后端:

          在腳本標(biāo)簽上設(shè)置crossorigin=“anonymous”

          在你的 HTML 源代碼中,為每一個腳本設(shè)置 Access-Control-Allow-Origin,在設(shè)置 SCRIPT 標(biāo)簽中,設(shè)置 crossorigin="anonymous"。在將 crossorigin 屬性添加到腳本標(biāo)簽之前,請確保正在向腳本文件發(fā)送 header。在 Firefox 中,如果 crossorigin 屬性存在但 Access-Control-Allow-Origin 標(biāo)題不存在,則腳本不會執(zhí)行。

          5. TypeError: Object Doesn’t Support Property

          當(dāng)調(diào)用未定義的方法時,IE 中會發(fā)生這樣的錯誤。

          這相當(dāng)于 Chrome 中的 “undefined’ is not a function” 錯誤。對于相同的邏輯錯誤,不同的瀏覽器可能會有不同的錯誤消息。

          這是在 IE 的 Web 應(yīng)用程序中使用 JavaScript 命名空間出現(xiàn)的一個常見問題。出現(xiàn)這種情況的絕大部分原因是IE無法將當(dāng)前名稱空間內(nèi)的方法綁定到this關(guān)鍵字。例如,如果你有 JS Rollbar 方法的命名空間 isAwesome。通常,如果位于 Rollbar 命名空間內(nèi),則可以使用以下語法調(diào)用該 isAwesome 方法:

          Chrome、Firefox 和 Opera 接受這種語法,IE則不接受。因此,使用 JS 命名空間時最安全的做法是:始終以實(shí)際名稱空間作為前綴。

          6. TypeError: ‘undefined’ Is Not a Function

          當(dāng)調(diào)用未定義的函數(shù)時,Chrome 中就會發(fā)生這樣的錯誤。

          隨著 JavaScript 編碼技術(shù)和設(shè)計模式在過去幾年中變得越來越復(fù)雜,回調(diào)和閉包中的自引用范圍也相應(yīng)增加,這是造成這種混亂現(xiàn)象的主要來源。

          正如下面的示例代碼片段:

          執(zhí)行上面的代碼會導(dǎo)致以下錯誤:“Uncaught TypeError: undefined is not a function。” 發(fā)生以上錯誤的原因是,當(dāng)你調(diào)用 setTimeout( ) 時,實(shí)際上是在調(diào)用 window.setTimeout( ),傳遞給 setTimeout( ) 的匿名函數(shù)是在窗口對象的上下文中定義的,而該窗口對象沒有 clearBoard( ) 方法。

          符合舊版瀏覽器的解決方案是以變量的方式簡單地將引用保存在 this 中,然后通過閉包繼承。例如:

          或者,在較新的瀏覽器中,使用 bind( ) 方法傳遞引用:

          7. Uncaught RangeError: Maximum Call Stack

          這是在很多種情況,Chrome 中發(fā)生的錯誤,一種情況是當(dāng)你調(diào)用一個不會終止的遞歸函數(shù)時。

          如果將值傳遞給超出范圍的函數(shù),也可能會發(fā)生這種情況。許多函數(shù)只接受特定范圍內(nèi)的數(shù)字輸入值。例如,Number.toExponential( digits ) 與 Number.toFixed( digits) 接受的參數(shù)范圍為從0到20,而 Number.toPrecision( digits ) 接受的數(shù)字范圍為從1至21。

          8. TypeError: Cannot Read Property ‘length’

          這是 Chrome 中發(fā)生的錯誤,因為讀取了未定義長度屬性的變量。

          通常在數(shù)組中能夠找到定義的長度,但是如果數(shù)組未初始化或變量名在另一個上下文中隱藏,則可能會出現(xiàn)這種錯誤。讓我們用下面的例子來解釋這種錯誤。

          當(dāng)用參數(shù)聲明一個函數(shù)時,這些參數(shù)會成為本地參數(shù)。這意味著即使你有名稱變量 testArray,函數(shù)中具有相同名稱的參數(shù)仍會被視為本地參數(shù)。

          有兩種方法可以解決這個問題:

          1. 刪除函數(shù)聲明語句中的參數(shù):

          2. 調(diào)用傳遞給我們聲明的數(shù)組函數(shù):

          9. Uncaught TypeError: Cannot Set Property

          當(dāng)嘗試訪問未定義的變量時,總會返回 undefined。我們也無法獲取或設(shè)置 undefined 的任何屬性。在這種情況下,應(yīng)用程序?qū)伋觥癠ncaught TypeError cannot set property of undefined”。

          例如,在 Chrome 瀏覽器中,如果 test 對象不存在,就會出現(xiàn)這種錯誤:

          所以就需要在訪問變量之前,對變量進(jìn)行定義。

          10. ReferenceError: Event Is Not Defined

          嘗試訪問未定義的變量或當(dāng)前范圍之外的變量時會引發(fā)此錯誤。

          如果在使用事件處理系統(tǒng)時遇到此錯誤,請確保使用傳入的事件對象作為參數(shù)。IE 這樣的瀏覽器提供了全局變量事件,Chrome 會自動將事件變量附加到處理程序中,F(xiàn)irefox 則不會自動添加事件變量。

          JavaScript 開發(fā)工具推薦

          SpreadJS 純前端表格控件是基于 HTML5 的 JavaScript 電子表格和網(wǎng)格功能控件,提供了完備的公式引擎、排序、過濾、輸入控件、數(shù)據(jù)可視化、Excel 導(dǎo)入/導(dǎo)出等功能,適用于 .NET、Java 和移動端等各平臺在線編輯類 Excel 功能的表格程序開發(fā)。

          結(jié)論

          事實(shí)證明很多這些 null 或 undefined 的錯誤是普遍存在的。 一個類似于 Typescript 這樣的好的靜態(tài)類型檢查系統(tǒng),當(dāng)設(shè)置為嚴(yán)格的編譯選項時,能夠幫助開發(fā)者避免這些錯誤。

          最后也希望通過本文,可以幫助開發(fā)者更好避免或是應(yīng)對以上的10種錯誤。

          avaScript與HTML之間的交互是通過事件實(shí)現(xiàn)的。事件,就是文檔或瀏覽器窗口中發(fā)生的一些特定的交互瞬間。可以使用偵聽器(或處理程序)來預(yù)定義事件,以便事件發(fā)生時執(zhí)行相應(yīng)的代碼。這種在傳統(tǒng)軟件工程中被稱為觀察者模式的模型,支持頁面的行為與頁面的外觀之間的松散耦合。

          事件最早是在IE3和NetscapeNavigator 2中出現(xiàn)的,當(dāng)時是作為分擔(dān)服務(wù)器運(yùn)算負(fù)載的一種手段。在IE4和Navigator4發(fā)布時,這兩種瀏覽器都提供了相似但不相同的API,這些API并存經(jīng)過了好幾個主要版本。DOM2級規(guī)范開始嘗試以一種符合邏輯的方式來標(biāo)準(zhǔn)化DOM事件。IE9、Firefox、Opera、Safari和Chrome全都實(shí)現(xiàn)了"DOM2級事件"模塊的核心部分。IE8是最后一個仍然使用其專有事件系統(tǒng)的主要瀏覽器。

          事件流

          當(dāng)瀏覽器發(fā)展到第四代時,瀏覽器開發(fā)團(tuán)隊遇到了一個很有意思的問題:頁面的哪一部分會擁有某個特定的事件?要明白這個問題問的是什么,可以想象畫在一張紙上的一組同心圓。如果把手指放在圓心上,那么指向的不是一個圓,而是紙上的所有圓。兩家公司的瀏覽器開發(fā)團(tuán)隊在看待瀏覽器事件方面還是一致的。如果單擊了某個按鈕,都認(rèn)為單擊事件不僅僅發(fā)生在按鈕上。也就是說,單擊按鈕的同時,也單擊了按鈕的容器元素,甚至也單擊了整個頁面。

          事件流描述的是從頁面中接收事件的順序。但有意思的是,IE和Netscape開發(fā)團(tuán)隊居然提出了差不多是完全相反的事件流的概念。IE的事件流是事件冒泡流,而Netscape Communicator的事件流是事件捕獲流。

          事件冒泡

          IE的事件流叫做事件冒泡,即事件開始時由最具體的元素(文檔中嵌套層次最深的那個節(jié)點(diǎn))接收,然后逐級向上傳播到較為不具體的節(jié)點(diǎn)(文檔)。所有現(xiàn)代瀏覽器都支持事件冒泡,但在具體實(shí)現(xiàn)上還是有一些差別。IE5.5及更早版本中的事件冒泡會跳過<html>元素(從<body>直接跳到document)。IE9、Firefox、Chrome和Safari則將事件一直冒泡到window對象。

          事件捕獲

          NetscapeCommunicator團(tuán)隊提出的另一種事件流叫做事件捕獲。事件捕獲的思想是不太具體的節(jié)點(diǎn)應(yīng)該更早接收到事件,而最具體的節(jié)點(diǎn)應(yīng)該最后接收到事件。事件捕獲的用以在于在事件到達(dá)預(yù)定目標(biāo)之前捕獲它。雖然事件捕獲是Netscape Communicator唯一支持的事件流模型,但I(xiàn)E9、Safari、Chrome、Opera和Firefox目前也支持這種事件流模型。盡管"DOM2級事件"規(guī)范要求事件應(yīng)該從document對象開始傳播,但這些瀏覽器都是從window對象開始捕獲事件的。

          DOM事件流

          "DOM2級事件"規(guī)定的事件流包括三個階段:事件捕獲階段、處于目標(biāo)階段和事件冒泡階段。首先發(fā)生的是事件捕獲,為截獲事件提供了機(jī)會。然后是實(shí)際的目標(biāo)接收到事件。最后一個階段是冒泡階段,可以在這個階段對事件做出響應(yīng)。

          事件處理程序

          事件就是用戶或瀏覽器自身執(zhí)行的某種動作。諸如click、load和mouseover,嗾使事件的名字。而響應(yīng)某個事件的函數(shù)就叫做事件處理程序(或事件偵聽器)。事件處理程序的名字以"on"開頭,因此click事件的事件處理程序就是onclick、load事件的事件處理程序就是onload。為事件指定處理程序的方式有好幾種。

          HTML事件處理程序

          某個元素支持的每種事件,都可以使用一個與相應(yīng)事件處理程序同名的HTML特性來指定。這個特性的值應(yīng)該是能夠執(zhí)行的JavaScript代碼。例如,要在按鈕被單擊時執(zhí)行一些JavaScript,可以像下面這樣編寫代碼:

          <input type="button"onclick="alert('Clicked')" value="Click!"/>

          當(dāng)單擊這個按鈕時,就會顯示一個警告框。這個操作是通過指定onclick特性并將一些JavaScript代碼作為它的值來定義的。由于這個值是JavaScript,因此不能在其中使用未經(jīng)轉(zhuǎn)義的HTML語法字符,例如和號(&)、雙引號("")、小于號(<)或大于號(>)。為了避免使用HTML實(shí)體,這里使用了單引號。如果想要使用雙引號,那么既要將代碼改成如下所示:

          <input type="button"onclick="alert("Clicked")" value="Click!"/>

          在HTML中定義的事件處理程序可以包含要執(zhí)行的具體動作,也可以調(diào)用在頁面其他地方定義的腳本。如下面的例子所示:

          <script type="text/javascript">

          function showMessage(){

          alert("Hello World!");

          }

          </script>

          <input type="button"onclick="showMessage()"value="Click!"/>

          在這個例子中,單擊按鈕就會調(diào)用showMessage()函數(shù)。這個函數(shù)是在一個獨(dú)立的<script>元素中定義的,當(dāng)然也可以被包含在一個外部文件中。事件處理程序中的代碼在執(zhí)行時,有權(quán)訪問全局作用域中的任何代碼。

          這樣指定事件處理程序具有一些獨(dú)到之處。首先,這樣會創(chuàng)建一個封裝著元素屬性值的函數(shù)。這個函數(shù)中有一個局部變量event,也就是事件對象。

          <!--輸出"click" -->

          <input type="button"onclick="alert(event.type)" value="Click!">

          通過event變量,可以直接訪問事件對象,不用自己定義它,也不用從函數(shù)的參數(shù)列表中讀取。在這個函數(shù)內(nèi)部,this值等于事件的目標(biāo)元素。

          <!--輸出"Click!" -->

          <input type="button"onclick="alert(this.value)" value="Click!">

          關(guān)于這個動態(tài)創(chuàng)建的函數(shù),另一個有意思的地方是它擴(kuò)展作用域的方式。在這個函數(shù)內(nèi)部,可以像訪問局部變量一樣訪問document及該元素本身的成員。這個函數(shù)使用with像下面這樣擴(kuò)展作用域:

          function funcName(){

          with(document){

          with(this){

          //元素屬性值

          }

          }

          }

          如此一來,事件處理程序要訪問自己的屬性就簡單多了。下面這行代碼與前面的例子效果相同:

          <!--輸出"Click!" -->

          <input type="button"onclick="alert(value)"value="Click!">

          如果當(dāng)前元素是一個表單輸入元素,則作用域中還會包含表單元素(父元素)的入口,這個函數(shù)就變成了如下所示:

          function funcName(){

          with(this.form){

          with(this){

          //元素屬性值

          }

          }

          }

          實(shí)際上,這樣擴(kuò)展作用域的方式無非就是想讓事件處理程序無需引用表單元素就能訪問其他表單字段。例如:

          <form method="post">

          <input type="text"name="username_" value="">

          <input type="button"value="Echo Username" onclick="alert(username_.value)">

          </form>

          在這個例子中,單擊按鈕會顯示文本框中的文本,值得注意的是,這里直接引用了username_元素。不過,在HTML中指定事件處理程序有兩個缺點(diǎn)。首先,存在一個時差問題。因為用戶可能會在HTML元素一出現(xiàn)在頁面上就觸發(fā)相應(yīng)的事件,但當(dāng)時的事件處理程序可能尚不舉杯執(zhí)行條件。以前面的例子來說明,假設(shè)showMessage()函數(shù)是在按鈕下方、頁面的最底部定義的。如果用戶在頁面解析showMessage()函數(shù)之前就點(diǎn)擊了按鈕,就會引發(fā)錯誤。為此,很多HTML事件處理程序就會被封裝在try-catch塊中,以便錯誤不會浮出水面。

          另一個缺點(diǎn)是,這樣擴(kuò)展時間處理程序的作用域鏈在不同瀏覽器中會導(dǎo)致不同結(jié)果。不同JavaScript引擎遵循的標(biāo)識符解析規(guī)則略有差異,很可能在訪問非限定對象成員時出錯。

          通過HTML指定時間處理程序的最后一個缺點(diǎn)是HTML與JavaScript代碼緊密耦合。如果要更換事件處理程序,就要改動兩個地方:HTML代碼和JavaScript代碼。而這也是許多開發(fā)人員摒棄HTML事件處理程序,轉(zhuǎn)而使用JavaScript指定時間處理程序的原因所在。

          DOM0 級事件處理程序

          通過JavaScript指定事件處理程序的傳統(tǒng)方式,就是將一個函數(shù)賦值給一個時間處理程序?qū)傩浴_@種為事件處理程序賦值的方法是在第四代Web瀏覽器中出現(xiàn)的,而且至今仍然為所有現(xiàn)代瀏覽器所支持。原因一是簡單,二是具有跨瀏覽器的優(yōu)勢。要使用JavaScript指定事件處理程序,首先必須取得一個要操作的對象的引用。

          每個元素(包括window和document)都有自己的事件處理程序?qū)傩裕@些屬性通常全部小寫,例如onclick。將這種屬性的值設(shè)置為一個函數(shù),就可以指定事件處理程序,如:

          varbtn=document.getElementById("myBtn");

          btn.onclick=function(){

          alert("Clicked");

          }

          在此,我們通過文檔對象取得了一個按鈕的引用,然后為它指定了onclick事件處理程序。但要注意,在這些代碼運(yùn)行以前不會指定事件處理程序,因此如果這些代碼在頁面中位于按鈕后面,就有可能在一段時間內(nèi)怎么單擊都沒有反應(yīng)。

          使用DOM 0 級方法指定的事件處理程序被認(rèn)為是元素的方法。因此,這時候的事件處理程序是在元素的作用域中運(yùn)行;換句話說,程序中的this引用當(dāng)前元素。可以在事件處理程序中通過this訪問元素的任何屬性和方法。以這種方式添加的事件處理程序會在事件流的冒泡階段被處理。

          也可刪除通過DOM0級方法指定的事件處理程序,只要像下面這樣將時間處理程序?qū)傩缘闹翟O(shè)置為null即可:

          btn.onclick=null;//刪除事件處理程序

          如果使用HTML指定事件處理程序,那么onclick屬性的值就是一個包含著在同名HTML特性中指定的代碼的函數(shù)。而將相應(yīng)的屬性設(shè)置為null,也可以刪除以這種方式指定的事件處理程序。

          DOM2級事件處理程序

          "DOM2級事件"定義了兩個方法,用于處理指定和刪除事件處理程序的操作:addEventListener()和removeEventListener()。所有DOM節(jié)點(diǎn)中都包含這兩個方法,并且它們都接受3個參數(shù):要處理的事件名、作為時間處理程序的函數(shù)和一個布爾值。最后這個布爾值參數(shù)如果是true,表示在捕獲階段調(diào)用事件處理程序;如果是false,表示在冒泡階段調(diào)用事件處理程序。

          要在click事件添加事件處理程序,可以使用下列代碼:

          varbtn=document.getElementById("myBtn");

          btn.addEventListener("click",function(){

          alert(this.id);

          },false);

          上面的代碼為一個按鈕添加了onclick事件處理程序,而且該事件會在冒泡階段被觸發(fā)(因為最后一個參數(shù)是false)。與DOM0級方法一樣,這里添加的事件處理程序也是在其依附的元素的作用域中運(yùn)行。使用DOM2級方法添加事件處理程序的主要好處是可以添加多個事件處理程序。如:

          varbtn=document.getElementById("myBtn");

          btn.addEventListener("click",function(){

          alert(this.id);

          },false);

          btn.addEventListener("click",function(){

          alert("Hello World");

          },false);

          這里為按鈕添加了兩個事件處理程序。這兩個事件處理程序會按照添加它們的順序觸發(fā),因此首先會顯示元素的ID,其次會顯示"Hello World"消息。

          通過addEventListener()添加的事件處理程序只能使用removeEventListener()來移除,移除時傳入的參數(shù)與添加時使用的參數(shù)相同。這也意味著通過addEventListener()添加的匿名函數(shù)將無法移除,如:

          varbtn=document.getElementById("myBtn");

          btn.addEventListener("click",function(){

          alert(this.id);

          },false);

          btn.removeEventListener("click",function(){//沒有用!

          alert(this.id);

          },false);

          在這個例子中,使用addEventListener()添加了一個事件處理程序。雖然調(diào)用removeEventListener()時看似使用了相同的參數(shù),但實(shí)際上,第二個參數(shù)與傳入addEventListener()中的那一個是完全不同的函數(shù)。而傳入removeEventListener()中的事件處理程序函數(shù)必須與傳入addEventListener()中的相同,如:

          var handler=function(){

          alert(this.id);

          }

          varbtn=document.getElementById("myBtn");

          btn.addEventListener("click",handler,false);

          btn.removeEventListener("click",handler,false);//有效

          重寫后的例子沒有問題,是因為在addEventListener()和removeEventListener()中使用了相同的函數(shù)。

          大多數(shù)情況下,都是將事件處理程序添加到事件流的冒泡階段,這樣可以最大限度地兼容各種瀏覽器。最好只在需要在事件達(dá)到目標(biāo)之前截獲它的時候?qū)⑹录幚沓绦蛱砑拥讲东@階段。如果不是特別需要,不建議在事件捕獲階段注冊事件處理程序。

          IE事件處理程序

          IE實(shí)現(xiàn)了與DOM中類似的兩個方法:attachEvent()和detachEvent()。這兩個方法接受相同的兩個參數(shù):事件處理程序名稱與事件處理程序函數(shù)。由于IE8及更早版本只支持事件冒泡,所以通過attachEvent()添加的事件處理程序都會被添加到冒泡階段。

          要使用attachEvent()為按鈕添加一個事件處理程序,可以使用以下代碼。

          varbtn=document.getElementById("myBtn");

          btn.attachEvent("onclick",function(){

          alert("Clicked");

          });

          注意,attachEvent()的第一個參數(shù)是"onclicke",而非DOM的addEventListener()方法中的"click"。

          在IE中使用attachEvent()與使用DOM0級方法的主要區(qū)別在于事件處理程序的作用域。在使用DOM0級方法的情況下,事件處理程序會在其所屬元素的作用域內(nèi)運(yùn)行;在使用attachEvent()方法的情況下,事件處理程序會在全局作用域中運(yùn)行,因此this等于window。在編寫跨瀏覽器的代碼時,牢記這一區(qū)別非常重要。

          與addEventListener()類似,attachEvent()方法也可以用來為一個元素添加多個事件處理程序。如:

          varbtn=document.getElementById("myBtn");

          btn.attachEvent("onclick",function(){

          alert("Clicked");

          });

          btn.attachEvent("onclick",function(){

          alert("Hello World");

          });

          這里,調(diào)用了兩次attachEvent(),為同一個按鈕添加了兩個不同的事件處理程序。不過,與DOM方法不同的是,這些事件處理程序不是以添加它們的順序執(zhí)行,而是以相反的順序被觸發(fā)。單擊這個例子中的按鈕,首先看到的是"Hello World",然后才是"Clicked"。

          使用attachEvent()添加的事件可以通過detachEvent()來移除,條件是必須提供相同的參數(shù)。

          IE11中需要使用addEventListener()和removeEventListener()。

          跨瀏覽器的事件處理程序

          為了以跨瀏覽器的方式處理事件,不少開發(fā)人員會使用能夠隔離瀏覽器差異的JavaScript庫,還有一些開發(fā)人員會自己開發(fā)最合適的事件處理的方法。自己編寫代碼其實(shí)也不難,只要恰當(dāng)?shù)厥褂媚芰z測即可。要保證處理事件的代碼能在大多數(shù)瀏覽器下一致地運(yùn)行,只需關(guān)注冒泡階段。

          第一個要創(chuàng)建的方法是addHandler(),它的職責(zé)是視情況分別使用DOM0級方法、DOM2級方法或IE方法來添加事件。這個方法屬于一個叫EventUtil的對象。addHandler()方法接受3個參數(shù):要操作的元素、事件名稱和事件處理程序函數(shù)。

          與addHandler()對應(yīng)的方法是removeHandler(),它也接受相同的參數(shù)。這個方法的職責(zé)是移除之前添加的事件處理程序——無論事件程序是采用什么方式添加到元素中的,如果其他方法無效,默認(rèn)采用DOM0級方法。

          var EventUtil={

          addHandler:function(element,type,handler){

          type=type.toLowerCase();

          type=type.substring(0,2)=="on"?type:"on"+type;

          if(element.addEventListener){

          element.addEventListener(type.substring(2),handler,false);

          }else if(element.attachEvent){

          element.attachEvent(type,handler);

          }else{

          element[type]=handler;

          }

          },

          removeHandler:function(element,type,handler){

          type=type.toLowerCase();

          type=type.substring(0,2)=="on"?type:"on"+type;

          if(element.removeEventListener){

          element.removeEventListener(type.substring(2),handler,false);

          }else if(element.detachEvent){

          element.detachEvent(type,handler);

          }else{

          element[type]=null;

          }

          }

          };

          這兩個方法首先都會檢測傳入的元素是否存在DOM2級方法。如果存在DOM2級方法,則使用該方法,其次是IE方法,最后是DOM0級方法。無論傳入的事件名稱是DOM類型的還是IE中的,都會自動匹配成適合的而且會進(jìn)行小寫轉(zhuǎn)換。使用上面方法時先獲取到element,定義好handler事件傳入對應(yīng)的方法中即可。

          事件對象

          在觸發(fā)DOM上的某個事件時,會產(chǎn)生一個事件對象event,這個對象中包含著所有與事件有關(guān)的信息。包括導(dǎo)致事件的元素、事件的類型以及其他與特定事件相關(guān)的信息。例如,鼠標(biāo)操作導(dǎo)致的事件對象中,會包含鼠標(biāo)位置的信息,而鍵盤操作導(dǎo)致的事件對象中,會包含與按下的鍵有關(guān)的信息。所有瀏覽器都支持event對象,但支持方式不同。

          DOM中的事件對象

          兼容DOM的瀏覽器會將一個event對象傳入到事件處理程序中。無論指定事件處理程序時使用什么方法(DOM0級或DOM2級),都會傳入event對象。event對象包含與創(chuàng)建它的特定事件有關(guān)的屬性和方法。觸發(fā)的事件類型不一樣,可用的屬性和方法也不一樣。不過,所有事件都會有下表列出的成員。

          屬性/方法類型讀/寫說明bubblesBoolean只讀表明事件是否冒泡cancelableBoolean只讀表名是否可以取消事件的默認(rèn)行為currentTargetElement只讀其事件處理程序當(dāng)前正在處理事件的那個元素defaultPreventedBoolean只讀為true表示已經(jīng)調(diào)用了preventDefault()detailInteger只讀與事件相關(guān)的細(xì)節(jié)信息eventPhaseInteger只讀調(diào)用事件處理程序的階段:1事件捕獲,2處于目標(biāo),3冒泡階段preventDefault()Function只讀取消事件的默認(rèn)行為。如果cancelable為true,可以使用這個方法stopImmediatePropagation()Function只讀取消事件的進(jìn)一步捕獲或冒泡,同時阻止任何事件處理程序被調(diào)用。stopPropagation()Function只讀取消事件的進(jìn)一步捕獲或冒泡。如果bubbles為true,則可以使用這個方法targetElement只讀事件的目標(biāo)trustedBoolean只讀為true表示事件是瀏覽器生成的,false表示事件是由開發(fā)人員通過JavaScript創(chuàng)建的typeString只讀被觸發(fā)的事件的類型viewAbstractView只讀與事件關(guān)聯(lián)的抽象視圖。等同于發(fā)生事件的window對象在事件處理程序內(nèi)部,對象this始終等于currentTarget的值,而target則只包含事件的實(shí)際目標(biāo)。如果直接將事件處理程序指定給了目標(biāo)元素,則this、currentTarget和target包含相同的值。

          在需要通過一個函數(shù)處理多個事件時,可以使用type屬性。下面使用事件對象做一個例子,模擬購物網(wǎng)站中鼠標(biāo)在圖片上時顯示該圖片的局部放大圖,點(diǎn)擊該圖片時,在新的網(wǎng)頁中顯示該圖片,需要做一些準(zhǔn)備:id為kitty的背景圖(beautykitty.jpg)的像素大小為該div的大小,將該圖片復(fù)制一份(beautykittybig.jpg),并調(diào)整大小為原圖片寬高x4。然后就可以實(shí)驗下面的例子了。

          <!DOCTYPE html>

          <html>

          <head>

          <meta charset="UTF-8">

          <title>Sample Page</title>

          </head>

          <body>

          <table>

          <tr>

          <td>

          <div id='kitty' style=";">

          <div id="SQ" style="position: relative;background:#2196F3;;"></div>

          </div>

          </td>

          <td>

          <div id='bigImg' style=";"></div>

          </td>

          </tr>

          </table>

          </body>

          <script type="text/javascript">

          var EventUtil={

          addHandler:function(element,type,handler){

          type=type.toLowerCase();

          type=type.substring(0,2)=="on"?type:"on"+type;

          if(element.addEventListener){

          element.addEventListener(type.substring(2),handler,false);

          }else if(element.attachEvent){

          element.attachEvent(type,handler);

          }else{

          element[type]=handler;

          }

          },

          removeHandler:function(element,type,handler){

          type=type.toLowerCase();

          type=type.substring(0,2)=="on"?type:"on"+type;

          if(element.removeEventListener){

          element.removeEventListener(type.substring(2),handler,false);

          }else if(element.detachEvent){

          element.detachEvent(type,handler);

          }else{

          element[type]=null;

          }

          }

          };

          varkitty=document.getElementById('kitty');

          var clickHandler=function(){

          window.open("http://localhost:8080/demo/fiels/beautykitty.jpg","HellKitty");

          }

          varmousemoveHandler=function(){

          var offsetX=(event.offsetX)*4;

          var offsetY=(event.offsetY)*4;

          var SQStyle=document.getElementById("SQ").style;

          SQStyle.visibility="visible";

          SQStyle.top=event.offsetY + "px";

          SQStyle.left=event.offsetX + "px";

          document.getElementById("bigImg").style.background="url('../fiels/beautykittybig.jpg')-"+offsetX+"px -"+offsetY+"px";

          }

          varmouseoutHandler=function(){

          document.getElementById("bigImg").style.background="gray";

          }

          EventUtil.addHandler(kitty,"onmousemove",mousemoveHandler);

          EventUtil.addHandler(kitty,"onclick",clickHandler);

          EventUtil.addHandler(kitty,"onmouseout",mouseoutHandler);

          </script>

          </html>

          做出來的效果就是:

          要阻止事件的默認(rèn)行為,可以使用preventDefault()方法。例如,連接的默認(rèn)行為就是在被單擊時會導(dǎo)航到其href特性指定的URL。如果項阻止連接導(dǎo)航這一默認(rèn)行為,那么通過連接的onclick事件處理程序就可以取消它,如:

          varlink=document.getElementById('myLink');

          link.onclick=function(){

          if(new Date().getHours() > 15){

          event.preventDefault();

          }

          }

          只有cancelable屬性設(shè)置為true的事件,才可以使用preventDefault()來取消其默認(rèn)行為。

          另外,stopPropagation()方法用于立即停止事件在DOM層次中的傳播,即取消進(jìn)一步的事件捕獲或冒泡。例如,直接添加到一個按鈕的事件處理程序可以調(diào)用stopPropagation(),從而避免觸發(fā)注冊在document.body上面的事件處理程序,如:

          varlink=document.getElementById('myLink');

          link.onclick=function(){

          alert('Link clicked!');

          event.preventDefault();

          event.stopPropagation();

          }

          document.body.onclick=function(){

          alert("Body clicked!");

          }

          對于這個例子而言,如果步調(diào)用stopPropagation(),就會在單擊連接時出現(xiàn)兩個警告框。調(diào)用stopPropagation()后click事件就不會傳播到document.body,因此就不會觸發(fā)注冊在這個元素上的onclick事件處理程序。

          事件對象的eventPhase屬性,可以用來確定事件當(dāng)前位于事件流的哪個階段。如果是在捕獲階段調(diào)用的事件處理程序,那么eventPhase等于1;如果事件處理程序處于目標(biāo)對象上,則eventPhase等于2;如果是在冒泡階段調(diào)用的事件處理程序,eventPhase等于3。這里要注意的是,盡管"處于目標(biāo)"發(fā)生在冒泡階段,但eventPhase仍然一直等于2。

          事件類型

          Web瀏覽器中可能發(fā)生的事件有很多類型。如前所述,不同的事件類型具有不同的信息,而"DOM3級事件"規(guī)定了以下幾類事件。

          UI(UserInterface,用戶界面)事件,當(dāng)用戶與頁面上的元素交互時觸發(fā);

          焦點(diǎn)事件,當(dāng)元素獲得或失去焦點(diǎn)時觸發(fā);

          鼠標(biāo)事件,當(dāng)用戶通過鼠標(biāo)在頁面上執(zhí)行操作時觸發(fā);

          滾輪事件,當(dāng)使用鼠標(biāo)滾輪(或類似設(shè)備)時觸發(fā);

          文本事件,當(dāng)在文檔中輸入文本時觸發(fā);

          鍵盤事件,當(dāng)用戶通過鍵盤在頁面上執(zhí)行操作時觸發(fā);

          合成事件,當(dāng)為IME(Input MethodEditor,輸入法編輯器)輸入字符時觸發(fā);

          變動事件,當(dāng)?shù)讓覦OM結(jié)構(gòu)發(fā)生變化時觸發(fā);

          變動名稱事件,當(dāng)元素或?qū)傩悦Q變動時觸發(fā)。此類事件已經(jīng)廢棄,沒有任何瀏覽器實(shí)現(xiàn)它們。

          除了這幾類事件之外,HTML5也定義了一組事件,而有些瀏覽器還會在DOM和BOM中實(shí)現(xiàn)其他專有事件。這些專有的事件一般都是根據(jù)開發(fā)人員需求定制的,沒有什么規(guī)范,因此不用瀏覽器的實(shí)現(xiàn)有可能也不一致。

          DOM3級事件模塊在DOM2級事件模塊基礎(chǔ)上重新定義了這些事件,也添加了一些新事件。包括IE9+在內(nèi)的所有主流瀏覽器都支持DOM2級事件。IE9+也支持了DOM3級事件。

          UI事件

          UI事件指的是那些不一定與用戶操作有關(guān)的事件。這些事件在DOM規(guī)范出現(xiàn)之前,都是以這種或那種形式存在的,而在DOM規(guī)范中保留是為了向后兼容。現(xiàn)有的UI事件如下。

          DOMActivate:表示元素已經(jīng)被用戶操作(通過鼠標(biāo)或鍵盤)激活。這個事件在DOM3級事件中被廢棄,但Firefox2+和Chrome支持它。考慮到不同瀏覽器實(shí)現(xiàn)的差異,不建議使用這個事件。

          load:當(dāng)頁面完全加載后在window上面觸發(fā),當(dāng)所有框架都加載完畢時在框架集上面觸發(fā),當(dāng)圖像加載完畢時在<img>元素上觸發(fā),或者當(dāng)嵌入的內(nèi)容加載完畢時在<object>元素上面觸發(fā)。

          unload:當(dāng)頁面完全卸載后在window上面觸發(fā),當(dāng)所有框架都卸載后在框架集上面觸發(fā),或者當(dāng)嵌入的內(nèi)容卸載完畢后在<object>元素上面觸發(fā)。

          abort:在用戶停止下載過程時,如果嵌入的內(nèi)容沒有加載完,則在<object>元素上面觸發(fā)。

          error:當(dāng)發(fā)生JavaScript錯誤時window上面觸發(fā),當(dāng)無法加載如想時在<img>元素上面觸發(fā),當(dāng)無法加載嵌入內(nèi)容時在<object>元素上面觸發(fā),或者當(dāng)有一或多geese框架無法加載時在框架集上面觸發(fā)。

          select:當(dāng)用戶選擇文本框(<input>或<textarea>)中的一或多個字符時觸發(fā)。

          resize:當(dāng)窗口或框架的大小變化時在window或框架上面觸發(fā)。

          scroll:當(dāng)用戶滾動帶滾動條的元素中的內(nèi)容時,在該元素上面觸發(fā)。<body>元素中包含加載頁面的滾動條。

          多數(shù)這些事件都與window對象或表單控件相關(guān)。

          處理DOMActivate之外,其他事件在DOM2級事件中都?xì)w為HTML事件(DOMActivate在DOM2級事件中仍然屬于UI事件)。要確定瀏覽器是否支持DOM2級事件規(guī)定的HTML事件,可以使用如下代碼:

          var isSupported=document.implementation.hasFeature("UIEvent","2.0");

          注意,只有根據(jù)"DOM2級事件"實(shí)現(xiàn)這些事件的瀏覽器才會返回true。而以非標(biāo)準(zhǔn)方式支持這些事件的瀏覽器則會返回false。要確定瀏覽器是否支持"DOM3級事件"定義的事件,可以使用如下代碼:

          var isSupported=document.implementation.hasFeature("UIEvent","3.0");

          load事件

          JavaScript中最常用的一個事件就是load。當(dāng)頁面完全加載后(包括所有圖像、JavaScript文件、CSS文件等外部資源),就會觸發(fā)window上面的load事件。有兩種定義onload事件處理程序的方式。第一種方式是使用如下的JavaScript代碼:

          EventUtil.addHandler(window,"load", function(event){

          alert("Loaded!");

          });

          這是通過JavaScript來指定事件處理程序的方式,使用的前面定義的跨瀏覽器的EventUtil對象。與添加其他事件一樣,這里也給事件處理程序傳入了一個event對象。這個event對象中不包含有關(guān)這個事件的任何附加信息,但在兼容DOM的瀏覽器中,event.target屬性的值會被設(shè)置為document。

          第二種指定onload事件處理程序的方式是為<body>元素添加一個onload特性。一般來說,在window上面發(fā)生的任何事件都可以在<body/>元素中通過相應(yīng)的特性來指定,因為在HTML中無法訪問window元素。實(shí)際上,這只是為了保證向后兼容的一種權(quán)宜之計,但所有瀏覽器都能很好地支持這種方式,建議盡可能使用JavaScript方式。

          圖像上面也可以觸發(fā)load事件,無論是在DOM中的圖像元素還是HTML中的圖像元素。因此可以在HTML中為任何圖像指定onload事件處理程序,例如:

          <img src="smile.gif" onload="alert('Imageloaded.')">

          這樣,當(dāng)例子中的圖像加載完畢后就會顯示一個警告框。同樣的功能還可以使用JavaScript來實(shí)現(xiàn)。

          還有一些元素也以非標(biāo)準(zhǔn)的方式支持load事件。在IE9+、Firefox、Opera、Chrome和Safari3+及更高版本中,<script>元素也會觸發(fā)load事件,以便開發(fā)人員確定動態(tài)加載的JavaScript文件是否加載完畢。與圖像不同,只有在設(shè)置了<script>元素的src屬性并將該元素添加到文檔后,才會開始下載JavaScript文件。換句話說,對于<script>元素而言,指定src屬性和指定事件處理程序的先后順序就不重要了。

          unload事件

          與load事件對應(yīng)的是unload事件,這個事件在文檔被完全卸載后觸發(fā)。只要用戶從一個頁面切換到另一個頁面,就會發(fā)生unload事件。而利用這個事件最多的情況是清除引用,以避免內(nèi)存泄漏。

          resize事件

          當(dāng)瀏覽器窗口被調(diào)整到一個新的高度或?qū)挾葧r,就會觸發(fā)resize事件。這個事件在window(窗口)上面觸發(fā),因此可以通過JavaScript或者<body>元素中的onresize特性來指定事件處理程序。

          關(guān)于何時會觸發(fā)resize事件,不同的瀏覽器有不同的機(jī)制。IE、Safari、Chrome和Opera會在瀏覽器窗口變化了1像素時就觸發(fā)resize事件,然后隨著變化不斷重復(fù)觸發(fā),應(yīng)該注意不要在這個事件的處理程序中加入大計算量的代碼,因為這些代碼可能被頻繁執(zhí)行,從而導(dǎo)致瀏覽器反應(yīng)明顯變慢。瀏覽器窗口最小化或最大化時也會觸發(fā)resize事件。

          scroll事件

          雖然scroll事件是在window對象上發(fā)生的,但它實(shí)際表示的則是頁面中相應(yīng)元素的變化。在混雜模式下,可以通過<body>元素的scrollLeft和scrollTop來監(jiān)控到這一變化;而在標(biāo)準(zhǔn)模式下,除Safari之外的所有瀏覽器都會通過<html>元素來反映這一變化(Safari仍然基于<body>跟蹤滾動位置)。

          與resize事件類似,scroll事件也會在文檔被滾動期間重復(fù)觸發(fā),所以有必要盡量保持事件處理程序的代碼簡單。

          焦點(diǎn)事件

          焦點(diǎn)事件會在頁面獲得或失去焦點(diǎn)時觸發(fā)。利用這些事件并與document.hasFocus()方法及document.activeElement屬性配合,可以知曉用戶在頁面上的行蹤。有以下6個焦點(diǎn)事件。

          blur:在元素失去焦點(diǎn)時觸發(fā)。這個事件不會冒泡;所有瀏覽器都支持它。

          DOMFocusIn:在元素獲得焦點(diǎn)時觸發(fā)。這個事件與HTML事件focus等價,但它冒泡。只有Opera支持這個事件。DOM3級事件廢棄了DOMFocusIn,選擇了focusin。

          DomFocusOut:在元素失去焦點(diǎn)時觸發(fā)。這個事件是HTML事件blur的通用版本。只有Opera支持這個事件。DOM3級事件廢棄了DomFocusOut,選擇了focusout。

          focus:在元素獲得焦點(diǎn)時觸發(fā)。這個事件不會冒泡;所有瀏覽器都支持它。

          focusin:在元素獲得焦點(diǎn)時觸發(fā)。這個事件與HTML事件focus等價,但它冒泡。

          focusout:在元素失去焦點(diǎn)時觸發(fā)。這個事件是HTML事件blur的通用版本。

          這一類事件中最主要的兩個是focus和blur,它們都是JavaScript早期就得到所有瀏覽器支持的事件。這些事件的最發(fā)問題是它們不冒泡。因此,IE的focusin和focusout與Opera的DOMFocusIn和DomFocusOut才會發(fā)生重疊。IE的方式最后被DOM3級事件采納為標(biāo)準(zhǔn)方式。

          當(dāng)從頁面中的一個元素移動到另一個元素,會依次觸發(fā)下列事件:

          (1) focusout在失去焦點(diǎn)的元素上觸發(fā);

          (2) focusin在獲得焦點(diǎn)的元素上觸發(fā);

          (3) blur在失去焦點(diǎn)的元素上觸發(fā);

          (4) DomFocusOut在數(shù)去焦點(diǎn)的元素上觸發(fā);

          (5) focus在獲得焦點(diǎn)的元素上觸發(fā);

          (6) DOMFocusIn在獲得焦點(diǎn)的元素上觸發(fā)。

          其中,blur、DomFocusOut和focusout的事件目標(biāo)是失去焦點(diǎn)的元素;而focus、DOMFocusIn和focusin的事件目標(biāo)是獲得焦點(diǎn)的元素。

          要確定瀏覽器是否支持這些事件,可以使用如下代碼:

          var isSupported=document.implementation.hasFeature("FocusEvent","3.0");

          鼠標(biāo)與滾輪事件

          鼠標(biāo)事件是Web開發(fā)中最常用的一類事件,畢竟鼠標(biāo)還是最主要的定位設(shè)備。DOM3級事件中定義了9個鼠標(biāo)事件:

          click:在用戶單擊鼠標(biāo)按鈕(一般是左邊的按鈕)或按下回車鍵時觸發(fā)。這一點(diǎn)對確保易訪問性很重要,意味著onclick事件處理程序既可以通過鍵盤也可以通過鼠標(biāo)執(zhí)行。

          dbclick:在用戶雙擊主鼠標(biāo)按鈕(一般是左邊的按鈕)時觸發(fā)。從技術(shù)上說,這個事件并不是DOM2級事件規(guī)范中規(guī)定的,但鑒于它得到了廣泛支持,所以DOM3級事件將其納入了標(biāo)準(zhǔn)。

          mousedown:在用戶按下了任意鼠標(biāo)按鈕時觸發(fā)。不能通過鍵盤觸發(fā)這個事件。

          mouseenter:在鼠標(biāo)從元素外部首次移動到元素范圍之內(nèi)時觸發(fā)。這個事件不冒泡,而且在光標(biāo)移動到后代元素上不會觸發(fā)。DOM2級事件并沒有定義這個事件,但DOM3級事件將它納入了規(guī)范。

          mouseleave:在位于元素上方的鼠標(biāo)光標(biāo)移動到元素范圍之外時觸發(fā)。這個事件不冒泡,而且在光標(biāo)移動到后代元素上不會觸發(fā)。DOM2級事件并沒有定義這個事件,但DOM3級事件將它納入了規(guī)范。

          mousemove:當(dāng)鼠標(biāo)指針在元素內(nèi)部移動時重復(fù)地觸發(fā)。不能通過鍵盤觸發(fā)這個事件。

          mouseout:在鼠標(biāo)指針位于一個元素上方,然后用戶將其一如另一個元素時觸發(fā)。又移入的另一個元素可能位于前一個元素的外部,也可能是這個元素的子元素。不能通過鍵盤觸發(fā)這個事件。

          mouseover:在鼠標(biāo)指針位于一個元素外部,然后用戶將其首次一如另一個元素邊界之內(nèi)時觸發(fā)。不能通過鍵盤觸發(fā)這個事件。

          mouseup:在用戶釋放鼠標(biāo)按鈕時觸發(fā)。不能通過鍵盤觸發(fā)這個事件。

          頁面上的所有元素都支持鼠標(biāo)事件。除了mouseenter和mouseleave,所有鼠標(biāo)事件都會冒泡,也可以被取消,而取消鼠標(biāo)事件將會影響瀏覽器的默認(rèn)行為。取消鼠標(biāo)事件的默認(rèn)行為還會影響其他事件,因為鼠標(biāo)事件與其他事件是密不可分的關(guān)系。

          只有在一個元素上相繼觸發(fā)mousedown和mouseup事件,才會觸發(fā)click事件;如果mousedown和mouseup中的一個被取消,就不會觸發(fā)click事件。類似地,只有觸發(fā)兩次click事件才會觸發(fā)依次dbclick事件。如果有代碼阻止了連續(xù)兩次觸發(fā)click事件(可能是直接取消click事件,也可能通過mousedown或mouseup間接實(shí)現(xiàn)),那么就不會觸發(fā)dbclick事件了。在onclick事件中出現(xiàn)了alert語句時也會阻止觸發(fā)dbclick事件,如下面的dbclick事件處理程序用于不會得到執(zhí)行:

          <button onclick="alert('Click')" ondblclick="alert('DBClick')">點(diǎn)擊</button>

          這4個事件觸發(fā)的順序始終如下:

          (1) mousedown

          (2) mouseup

          (3) click

          (4) mousedown

          (5) mouseup

          (6) click

          (7) dbclick

          顯然,click和dbclick事件都會依賴與其他事件的觸發(fā);然而mousedown和mouseup則不受其他事件的影響。

          使用以下代碼可以檢測瀏覽器是否支持以上DOM2級事件(除dbclick、mouseenter和mouseleave之外):

          var isSupported=document.implementation.hasFeature("MouseEvents","2.0");

          要檢測瀏覽器是否支持上面的所有事件,可以使用以下代碼:

          var isSupported=document.implementation.hasFeature("MouseEvent","3.0");

          注意,DOM3級事件的feature名是"MouseEvent",而非"MouseEvents"

          客戶區(qū)坐標(biāo)位置

          鼠標(biāo)事件都是在瀏覽器視口的特定位置上發(fā)生的。這個位置信息保存在事件對象的clientX和clientY屬性中。所有瀏覽器都支持兩個屬性,它們的值表示事件發(fā)生時鼠標(biāo)在視口中的水平和垂直坐標(biāo)。

          可以使用類似下列代碼取得鼠標(biāo)事件的客戶坐標(biāo)信息,可在頁面中看到隨著鼠標(biāo)的移動,坐標(biāo)的顯示跟隨變化:

          <body style="background-color:antiqueWhite;height:1000px">

          <label id="position"style="">(000,000)</label>

          </body>

          <script type="text/javascript">

          var EventUtil={

          addHandler:function(element,type,handler){

          type=type.toLowerCase();

          type=type.substring(0,2)=="on"?type:"on"+type;

          if(element.addEventListener){

          element.addEventListener(type.substring(2),handler,false);

          }else if(element.attachEvent){

          element.attachEvent(type,handler);

          }else{

          element[type]=handler;

          }

          },

          removeHandler:function(element,type,handler){

          type=type.toLowerCase();

          type=type.substring(0,2)=="on"?type:"on"+type;

          if(element.removeEventListener){

          element.removeEventListener(type.substring(2),handler,false);

          }else if(element.detachEvent){

          element.detachEvent(type,handler);

          }else{

          element[type]=null;

          }

          }

          };

          var label=document.getElementById("position");

          var showCoordinate=function(event){

          var position="(" + event.clientX + " , " + event.clientY + ")";

          label.innerText=position;

          label.style.paddingTop=(event.clientY-20)+"px";

          label.style.paddingLeft=(event.clientX-50)+"px";

          }

          EventUtil.addHandler(document,"onmousemove",showCoordinate);

          </script>

          頁面坐標(biāo)位置

          通過客戶區(qū)坐標(biāo)能夠知道鼠標(biāo)是在視口中什么位置,而頁面坐標(biāo)通過事件對象的pageX和pageY屬性,能夠告訴你事件是在頁面中什么位置發(fā)生的。換句話說,這兩個屬性表示鼠標(biāo)光標(biāo)在頁面中的位置,因此坐標(biāo)是從頁面本身而非視口的左邊和定邊計算的。

          在頁面沒有滾動的情況下,pageX和pageY的值與clientX和clientY的值相等。

          IE8及更早版本不支持事件對象上的頁面坐標(biāo),不過使用客戶區(qū)坐標(biāo)和滾動信息可以計算出來。這個時候需要用到document.body(混雜模式)或document.documentElement(標(biāo)準(zhǔn)模式)中的scrollLeft和scrollTop屬性。

          屏幕坐標(biāo)位置

          鼠標(biāo)事件發(fā)生時,不僅會有相對于瀏覽器窗口的位置,還有一個相對于整個電腦屏幕的位置。而通過screenX和screenY屬性就可以確定鼠標(biāo)事件發(fā)生時鼠標(biāo)指針相對于整個屏幕的坐標(biāo)信息。

          修改鍵

          雖然鼠標(biāo)事件主要是使用鼠標(biāo)來觸發(fā)的,但在按下鼠標(biāo)時鍵盤上某些鍵的狀態(tài)也可以影響到索要采取的操作。這些修改鍵就是Shfit、Ctrl、Alt和Meat(在Windows鍵盤中是Windows鍵,在蘋果機(jī)中是Cmd鍵),它們經(jīng)常被用來修改鼠標(biāo)事件的行為。DOM為此規(guī)定了4個屬性,表示這些修改鍵的狀態(tài):shfitKey、ctrlKey、altKey和metaKey。這些屬性中包含的都是布爾值,如果相應(yīng)的鍵被按下了,則值為true,否則為false。當(dāng)某個鼠標(biāo)事件發(fā)生時,通過檢測這幾個屬性就可以確定用戶是否同時按下了其中的鍵。如:

          EventUtil.addHandler(btn,"click",function(event){

          var keys=new Array();

          if(event.shiftKey){

          keys.push("shfit");

          }

          if(event.ctrlKey){

          keys.push("ctrl");

          }

          if(event.altKey){

          keys.push("alt");

          }

          if(event.metaKey){

          keys.push("meta");

          }

          console.log("keys:" + keys.join(","));

          });

          相關(guān)元素

          在發(fā)生mouseover和mouseout事件時,還會涉及更多的元素。這兩個事件都會涉及把鼠標(biāo)指針從一個元素的邊界之內(nèi)移動到另一個元素的邊界之內(nèi)。對mouseover事件而言,事件的主要目標(biāo)是獲得光標(biāo)的元素,而相關(guān)元素就是哪個失去光標(biāo)的元素。類似地,對mouseout事件而言,事件的主要目標(biāo)是失去光標(biāo)的元素,而相關(guān)元素則是光標(biāo)的元素。

          鼠標(biāo)按鈕

          只有在主鼠標(biāo)按鈕被單擊(或鍵盤回車被按下)時才會觸發(fā)click事件,因此檢測按鈕的信息并不是必要的。但對于mousedown和mouseup事件來說,則在其event對象存在一個button屬性,表示按下或釋放的按鈕。DOM的button屬性可能有如下3個值:0表示主鼠標(biāo)按鈕,1表示中間的鼠標(biāo)滾輪,2表示次鼠標(biāo)按鈕。在常規(guī)的設(shè)置中,主鼠標(biāo)按鈕就是鼠標(biāo)左鍵,而次鼠標(biāo)按鈕就是鼠標(biāo)右鍵。

          更多的事件信息

          "DOM2級事件"規(guī)范在event對象中還提供了detail屬性,用于給出有關(guān)事件的更多信息。對于鼠標(biāo)事件來說,detail中包含了一個數(shù)值,表示在給定位置上發(fā)生了多少次單擊。在同一個像素上相繼地發(fā)生一次mousedown和一次mouseup事件算作一次單擊。details屬性從1開始計數(shù),每次單擊發(fā)生后都會遞增。如果鼠標(biāo)在mousedown和mouseup之間移動了位置,則details會被重置為0。

          鼠標(biāo)滾輪事件

          IE6.0首先實(shí)現(xiàn)了mousewheel事件。此后,Opera、Chrome和Safari也都實(shí)現(xiàn)了這個事件。當(dāng)用戶通過鼠標(biāo)滾輪與頁面交互、在垂直方向上滾動頁面時(無論是向上還是向下),就會觸發(fā)mousewheel事件。這個事件可以在任何元素上面觸發(fā),最終會冒泡到document(IE8)或window(IE9、Opera、Chrome及Safari)對象。與mousewheel事件對應(yīng)的event對象除包含鼠標(biāo)事件的所有標(biāo)準(zhǔn)信息外,還包含一個特殊的wheelDelta屬性。當(dāng)用戶向前滾動鼠標(biāo)滾輪時,wheelDelta是120的倍數(shù);當(dāng)向后時,是-120的倍數(shù)。

          鍵盤與文本事件

          用戶在使用鍵盤時會觸發(fā)鍵盤事件。"DOM2"級事件最初規(guī)定了鍵盤事件,但在最終定稿之前又刪除了相應(yīng)的內(nèi)容。結(jié)果,對鍵盤事件的支持主要遵循的是DOM0級。

          "DOM3級事件"為鍵盤事件制定了規(guī)范,有3個鍵盤事件:

          keydown:當(dāng)用戶按下鍵盤上的任意鍵時觸發(fā),而且如果按住不放的話,會重復(fù)觸發(fā)此事件。

          keypress:當(dāng)用戶按下鍵盤上的字符鍵時觸發(fā),而且按住不放的話,會重復(fù)觸發(fā)此事件。按下Esc鍵也會觸發(fā)這個事件。

          keyup:當(dāng)用戶釋放鍵盤上的鍵時觸發(fā)。

          雖然所有元素都支持以上3個事件,但只有在用戶通過文本框輸入文本時才最常用到。

          只有一個文本事件:textInput。這個事件是對keypress的補(bǔ)充,用以是在將文本顯示給用戶之前更容易攔截文本。在文本插入文本框之前會觸發(fā)textInput事件。

          在用戶按了一下鍵盤上的字符鍵時,首先會觸發(fā)keydown事件,然后緊跟著是keypress事件,最后會觸發(fā)keyup事件。其中keydown和keypress都是在文本框發(fā)生變化之前被觸發(fā)的;而keyup事件則是在文本框已經(jīng)發(fā)生變化之后被觸發(fā)的。如果用戶按下了一個字符鍵不放,就會重復(fù)觸發(fā)keydown和keypress事件,知道用戶松開該鍵為止。

          如果用戶按下的是一個非字符鍵,那么首先會觸發(fā)keydown事件,然后就是keyup事件。如果按住這個非字符鍵不放,那么就會一直重復(fù)觸發(fā)keydown事件,直到用戶松開這個鍵,此時會觸發(fā)keyup事件。

          鍵盤事件與鼠標(biāo)事件一樣,都支持相同的修改鍵。而且,鍵盤事件的事件對象中也有shfitKey、ctrlKey、altKey和metaKey屬性。IE8及低版本不支持metaKey。

          鍵碼

          在發(fā)生keydown和keyup事件時,event對象的keyCode屬性中會包含一個代碼,與鍵盤上一個特定的鍵對應(yīng)。對數(shù)字字母字符鍵,keyCode屬性的值與ASCII碼中對應(yīng)小寫字母或數(shù)字的編碼相同。因此,數(shù)字鍵7的keyCode值為55,而字母A鍵的keyCode值為65——與Shfit的狀態(tài)無關(guān)。DOM和IE的event對象都支持keyCode屬性。無論keydown或keyup事件都會存在一些特殊情況。在Firefox和Opera中,按分號鍵時keyCode值為59,也就是ASCII分號中的編碼;但I(xiàn)E和Safari返回186,即鍵盤中按鍵的鍵碼。

          字符編碼

          發(fā)生keypress事件意味著按下的鍵會影響到屏幕中文本的顯示。在所有瀏覽器中,按下能夠插入或刪除的鍵都會觸發(fā)keypress事件;按下其他鍵能夠觸發(fā)此事件因瀏覽器而異。

          IE9、Firefox、Chrome和Safari的event對象都支持一個charCode屬性,這個屬性只有在發(fā)生keypress事件時才包含值,而且這個值是按下的那個鍵所代表字符的ASCII編碼。此時的keyCode通常等于0或者也有可能所按鍵的鍵碼。IE8及之前版本和Opera則是在keyCode中保存字符的ASCII編碼。要想以跨瀏覽器的方式取得字符編碼,首先必須檢測charCode屬性是否可用,如果不可用則使用keyCode,如下所示:

          var EventUtil={

          //……

          getCharCode:function(event){

          if(typeof event.charCode=="number"){

          return event.charCode;

          }else{

          return event.keyCode;

          }

          }

          //……

          };

          這個方法首先檢測charCode屬性是否包含數(shù)值(在不支持這個屬性的瀏覽器中,值為undefined),如果是返回該值,否則返回keyCode屬性值。在取得了字符編碼之后,就可以使用String.fromCharCode()將其轉(zhuǎn)換成實(shí)際的字符。

          DOM3級變化

          盡管所有瀏覽器都實(shí)現(xiàn)了某種形式的鍵盤事件,DOM3級事件還是做出了一些改變。比如,DOM3級事件中的鍵盤事件,不再包含charCode屬性,而是包含兩個新屬性:key和char。

          其中,key屬性是為了取代keyCode而新增的,它的值是一個字符串。在按下某個字符鍵時,key的值就是相應(yīng)的文本字符(如"k"或"M");在按下非字符鍵時,key的值是相應(yīng)鍵的名(如"Shift"或"Down")。而char屬性在按下字符鍵時的行為與key相同,但在按下非字符鍵時值為null。

          IE9支持key屬性,但不支持char屬性。Safari5和Chrome支持名為keyIdentifier的屬性,在按下非字符鍵(例如Shfit)的情況下與key的值相同。對于字符鍵,keyIdentifier返回一個格式類似"U+0000"的字符串,表示Unicode值。

          textInput事件

          "DOM3級事件"規(guī)范中引入了一個新事件,名叫textInput。根據(jù)規(guī)范,當(dāng)用戶在可編輯區(qū)域中輸入字符時,就會觸發(fā)這個事件。這個用于替代keypress的textInput事件的行為稍微有不同。區(qū)別之一就是任何可以獲得焦點(diǎn)的元素都可以觸發(fā)keypress時間愛你,但只有可編輯區(qū)才能觸發(fā)textInput事件。區(qū)別之二是textInput事件只會在用戶按下能夠輸入實(shí)際字符的鍵時才會被觸發(fā),而keypress事件則在按下哪些能夠影響文本顯示的鍵時也會觸發(fā)(例如退格鍵)。

          由于textInput事件主要考慮的是字符,因此它的event對象中還包含一個data屬性,這個屬性的值就是用戶輸入的字符(而非字符編碼)。換句話說,用戶在沒有按上檔鍵的情況下按下了S鍵,data的值就是"s",而如果在按住上檔鍵時按下該鍵,data的值就是"S"。

          復(fù)合事件

          復(fù)合事件是DOM3級事件中新添加的一類事件,用于處理IME的輸入序列。IME(Input Method Editor,輸入法編輯器)可以讓用戶輸入在物理鍵盤上找不到的字符。例如,使用拉丁文鍵盤的用戶通過IME照樣能輸入日文字符。IME通常需要同時按住多個見,但最終只輸入一個字符。復(fù)合事件就是針對檢測和處理這種輸入而設(shè)計的。有以下三種復(fù)合事件。

          compositionstart:在IME的文本復(fù)合系統(tǒng)打開時觸發(fā),表示要開始輸入了。

          compositionupdate:在向輸入字段中插入新字符時觸發(fā)。

          compositionend:在IME的文本復(fù)合系統(tǒng)關(guān)閉時觸發(fā),表示返回正常鍵盤輸入狀態(tài)。

          復(fù)合事件與文本事件在很多方面都很相似。在觸發(fā)復(fù)合事件時,目標(biāo)是接收文本的輸入字段。但它比文本事件的事件對象多一個屬性data,其中包含以下幾個值中的一個:

          如果在compositionstart事件發(fā)生時訪問,包含正在編輯的文本(例如,已經(jīng)選中的需要馬上替換的文本);

          如果在compositionupdate事件發(fā)生時訪問,包含正插入的新字符;

          如果在compositionend事件發(fā)生時訪問,包含此次輸入會話中插入的所有字符。

          到2016年,大多數(shù)的主流瀏覽器(Safari除外)都已支持復(fù)合事件,要確定瀏覽器是否支持復(fù)合事件,可以使用以下代碼:

          var isSupported=document.implementation.hasFeature("CompositionEvent","3.0");

          變動事件

          DOM2級的變動事件能在DOM中的某一部分發(fā)生變化時給出提示。變動事件是為XML或HTML DOM設(shè)計的,并不特定于某種語言。DOM2級定義了如下變動事件。

          DOMSubtreeModified:在DOM結(jié)構(gòu)中發(fā)生任何變化時觸發(fā)。這個事件在其他任何事件觸發(fā)后都會觸發(fā)。

          DOMNodeInserted:在一個節(jié)點(diǎn)作為子節(jié)點(diǎn)被插入到另一個節(jié)點(diǎn)中時觸發(fā)。

          DOMNodeRemoved:在節(jié)點(diǎn)從其父節(jié)點(diǎn)中被移除時觸發(fā)。

          DOMNodeInsertedIntoDocument:在一個節(jié)點(diǎn)被直接插入文檔或通過子樹直接插入文檔之后觸發(fā)。這個事件在DOMNodeInserted之后觸發(fā)。

          DOMNodeRemovedFromDocument:在一個節(jié)點(diǎn)被直接從文檔中移除或通過子樹間接從文檔中移除之前觸發(fā)。這個事件在DOMNodeRemoved之后觸發(fā)。

          DOMAttrModified:在特性被修改之后觸發(fā)。

          DOMCharacterDataModified:在文本節(jié)點(diǎn)的值發(fā)生變化時觸發(fā)。

          使用下列代碼可以檢測出瀏覽器是否支持變動事件:

          var isSupported=document.implementation.hasFeature("MutationEvents","2.0");

          刪除節(jié)點(diǎn)

          在使用removeChild()或replaceChild()從DOM中刪除節(jié)點(diǎn)時,首先會觸發(fā)DOMNodeRemoved事件。這個事件的目標(biāo)(event.target)是被刪除的節(jié)點(diǎn),而event.relatedNode屬性中包含著對目標(biāo)節(jié)點(diǎn)父節(jié)點(diǎn)的引用。在這個事件觸發(fā)時,節(jié)點(diǎn)尚未從其父節(jié)點(diǎn)刪除,因此其parentNode屬性仍然指向父節(jié)點(diǎn)(與event.relatedNode相同)。這個事件會冒泡,因而可以在DOM的任何層次上面處理它。

          如果被移除的子節(jié)點(diǎn)包含子節(jié)點(diǎn),那么在其所有子節(jié)點(diǎn)及這個被移除的節(jié)點(diǎn)上會相繼觸發(fā)DOMNodeRemovedFromDocument事件。這個事件不會冒泡,所以只有直接指定給其中一個子節(jié)點(diǎn)的事件處理程序才會被調(diào)用。這個事件的目標(biāo)是相應(yīng)的子節(jié)點(diǎn)或者那個被移除的節(jié)點(diǎn),除此之外event對象中不包含其他信息。

          緊隨其后觸發(fā)的是DOMSubtreeModified事件。這個事件的目標(biāo)是移除節(jié)點(diǎn)的父節(jié)點(diǎn);此時的event對象也不會提供與事件相關(guān)的其他信息。

          插入節(jié)點(diǎn)

          在使用appendChild()、replaceChild()或insertBefore()向DOM中插入節(jié)點(diǎn)時,相繼觸發(fā)的事件為:DOMNodeInserted(冒泡)、DOMNodeInsertedIntoDocument(不冒泡)、DomSubtreeModified。

          HTML5事件

          DOM規(guī)范中沒有涵蓋所有瀏覽器支持的所有事件。很多瀏覽器出于不同的目的——滿足用戶需求或解決特殊問題,還實(shí)現(xiàn)了一些自定義的事件。HTML5詳盡列出了瀏覽器應(yīng)該支持的所有事件。

          contextmenu事件

          表示合適應(yīng)該顯示上下文菜單,以便開發(fā)人員取消默認(rèn)的上下文菜單而提供自定義的菜單。該事件冒泡。在所有瀏覽器中都可以取消這個事件:在兼容DOM的瀏覽器中,使用event.preventDefault();在IE中,將event.returnValue的值設(shè)置為false。

          Beforeunload事件

          之所以有發(fā)生在window對象上的beforeunload事件,是為了讓開發(fā)人員有可能在頁面卸載前阻止這一操作。這個事件會在瀏覽器卸載頁面之前觸發(fā),可以通過它來取消卸載并繼續(xù)使用原有頁面。但是不能徹底取消這個事件,因為那就相當(dāng)于讓用戶無法離開當(dāng)前頁面了。為此,這個事件的意圖是將控制權(quán)交給用戶,顯示的消息會告知用戶頁面將被卸載,詢問用戶是否真的要關(guān)閉頁面,還是希望繼續(xù)留下來。類似事件的應(yīng)用場景很多,比如有些電腦程序退出時會詢問是否退出,網(wǎng)頁游戲在關(guān)閉網(wǎng)頁時會詢問是否再多玩一會……

          DOMContentLoaded事件

          如前所述,window的load事件會在頁面中的一切都加載完畢時觸發(fā),但這個過程可能會因為要加載的外部資源過多而頗費(fèi)周折。而DOMContentLoaded事件則在形成完整的DOM樹之后就會觸發(fā),不理會圖像、JavaScript文件、CSS文件或其他資源是否已經(jīng)下載完畢。與load事件不同,DOMContentLoaded支持在頁面下載的早起添加事件處理程序,這也就意味著用戶能夠盡早地與頁面進(jìn)行交互。

          要處理DOMContentLoaded事件,可以為document或window添加相應(yīng)的事件處理程序(盡管這個事件會冒泡到window,但它的實(shí)際目標(biāo)實(shí)際上是document)。DOMContentLoaded事件對象不會提供任何額外的信息。IE9+、Firefox、Chrome、Safari3.0+和Opera9+都支持DOMContentLoaded事件,通常這個事件既可以添加事件處理程序,也可以執(zhí)行其他DOM操作。這個事件始終都會在load事件之前觸發(fā)。

          內(nèi)存和性能

          為頁面添加大量的處理程序?qū)⒔档晚撁娴恼w運(yùn)行性能。導(dǎo)致這一問題的原因是多方面的。首先,每個函數(shù)都是對象,都會占用內(nèi)存;內(nèi)存中的對象越多,性能就越差。其次,必須事先指定所有事件處理程序而導(dǎo)致的DOM訪問次數(shù),會延遲整個頁面的交互就緒時間。

          事件委托

          對"事件處理程序過多"問題的解決方案就是事件委托。事件委托利用了事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件。例如,click事件會一直冒泡到document層次。也就是說,可以為整個頁面指定一個onclick事件處理程序,而不必給每個可單擊的元素分別添加事件處理程序。


          最適合采用事件委托技術(shù)的事件包括click、mousedown、mouseup、keydown、keyup和keypress。雖然mouseover和mouseout事件也冒泡,但要適當(dāng)處理他們并不容易,而且經(jīng)常需要計算元素的位置(因為當(dāng)鼠標(biāo)從一個元素移到其子節(jié)點(diǎn)時,或者當(dāng)鼠標(biāo)移出該元素時,都會觸發(fā)mouseout事件)。

          移除事件處理程序

          每當(dāng)將事件處理程序指定給元素時,運(yùn)行中的瀏覽器代碼與支持頁面交互的JavaScript代碼之間就會建立一個連接。當(dāng)事件處理程序不再使用時,應(yīng)該在適當(dāng)?shù)臅r機(jī)將其去除。

          模擬事件

          事件,就是網(wǎng)頁中某個特別值得關(guān)注的瞬間。事件經(jīng)常由用戶操作或通過其他瀏覽器功能來觸發(fā)。但很少有人知道,可以使用JavaScript在任意時刻來觸發(fā)特定的事件,而此時的事件就如同瀏覽器創(chuàng)建的事件一樣。也就是說,這些事件該冒泡還會冒泡,而且按照能夠?qū)е聻g覽器執(zhí)行已經(jīng)指定的處理他們的事件處理程序。在測試Web應(yīng)用程序,模擬觸發(fā)事件是一種極其有用的技術(shù)。DOM2級規(guī)范為此規(guī)定了模擬特定事件的方式。IE9,Opera、Firefox、Chrome和Safari都支持這種方式。IE有它自己模擬事件的方式。

          DOM中的事件模擬

          可以在document對象上使用createEvent()方法創(chuàng)建event對象。這個方法接收一個參數(shù),即表示要創(chuàng)建的事件類型的字符串。在DOM2級中,所有這些字符串都使用英文復(fù)數(shù)形式,而在DOM3級中都變成了單數(shù)。這個字符串可以是下列幾個字符串之一:UIEvents、MouseEvents、MutationEvents和HTMLEvents。

          創(chuàng)建完成事件對象后,可以調(diào)用事件對象的initXXX()方法,為該事件對象指定具體的屬性,然后調(diào)用HTML對象的dispatchEvent()方法完成事件的模擬,如:

          var btn=document.getElementById("myBtn");

          var event=document.createEvent("MouseEvents");

          event.initMouseEvent("click",true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);

          btn.dispatchEvent(event);


          主站蜘蛛池模板: 91一区二区三区| tom影院亚洲国产一区二区| 中文字幕一区二区免费 | 久久精品免费一区二区三区 | 国产a久久精品一区二区三区| 视频在线观看一区二区| 国产精品伦一区二区三级视频| 亚洲国产激情在线一区| 中文字幕永久一区二区三区在线观看 | 秋霞无码一区二区| 精品国产一区二区三区久久蜜臀| 久久久精品人妻一区二区三区蜜桃 | 韩国女主播一区二区| 国产一区二区三区不卡AV| 日韩精品一区二区三区老鸦窝| 精品人妻无码一区二区三区蜜桃一 | 日韩精品一区二区三区中文 | 精品一区二区在线观看| 精品一区二区三区水蜜桃| 亚洲欧美成人一区二区三区| 亚洲视频一区调教| 久久亚洲一区二区| 久久99热狠狠色精品一区| 亚洲永久无码3D动漫一区| 国产福利电影一区二区三区,日韩伦理电影在线福 | 91精品国产一区二区三区左线 | 国产亚洲3p无码一区二区| 精品视频一区在线观看| 白丝爆浆18禁一区二区三区| 国产伦精品一区二区三区无广告 | 免费一区二区无码视频在线播放| 国产综合精品一区二区| 色综合久久一区二区三区| 91国偷自产一区二区三区| 亚洲大尺度无码无码专线一区| 日本一区视频在线播放| 国产伦一区二区三区高清 | 亚洲国产视频一区| 亚洲一区二区三区成人网站| 亚洲一区二区三区在线视频| 在线播放偷拍一区精品|