国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

Web 事件機制研究

2021-04-13 01:34羅才華劉小園
關(guān)鍵詞:列表瀏覽器網(wǎng)頁

羅才華,劉小園

(羅定職業(yè)技術(shù)學(xué)院信息工程系,廣東羅定,527200)

1 事件與事件對象

Web 事件是html 與JavaScript 之間進(jìn)行交互的載體與橋梁,是文檔或瀏覽器窗口中發(fā)生的一些特定的交互瞬間,如用戶鼠標(biāo)經(jīng)過或點擊某個特定元素、按下鍵盤上某個按鍵、瀏覽器窗口大小發(fā)生改變、頁面加載與頁面滾動等動作都屬于Web 事件[1]。事件最早是作為分擔(dān)服務(wù)器運算負(fù)載的一種手段出現(xiàn)在IE3 和Netscape Navigator2 中,后來DOM2 級規(guī)范開始嘗試以一種符合邏輯的方式來標(biāo)準(zhǔn)化DOM事件,目前主要瀏覽器都已經(jīng)實現(xiàn)了“DOM2 級事件”[2]。事件通過監(jiān)聽頁面的變化或者用戶對頁面或瀏覽器執(zhí)行的動作,從而執(zhí)行某些指定的JavaScript 代碼段,達(dá)到實現(xiàn)某些功能的目的。

事件對象是一個包含事件具體信息的對象。該對象在事件發(fā)生時產(chǎn)生,并在該事件處理程序函數(shù)中以參數(shù)的形式出現(xiàn),通常命名為event。比如,用戶在頁面中點擊了某個元素,那么在產(chǎn)生一個事件的同時也生成了一個事件對象,該對象中包含著事件的具體信息,并可以從該對象獲取到這個事件的類型和觸發(fā)這個事件的具體元素。如果事件是由鼠標(biāo)觸發(fā),對象中會包含鼠標(biāo)觸發(fā)時的位置信息;如果事件是由鍵盤的觸發(fā),對象中則會包含具體的按鍵信息等。

2 事件流

在網(wǎng)頁中,元素是具有層級關(guān)系的。當(dāng)用戶從瀏覽器打開一個網(wǎng)頁時,這個網(wǎng)頁的層級關(guān)系依次為:window →document →html →body →div(或某個具體的元素)。當(dāng)用戶點擊了一個div 元素(或其他元素)時,不僅點擊了元素本身,也點擊了元素的容器,甚至點擊了整個頁面,那么除了被點擊的元素會觸發(fā)事件之外,body、html 等元素也會觸發(fā)事件。因為元素間存在包含關(guān)系,那么事件的觸發(fā)就涉及到觸發(fā)順序的問題。

事件流用來說明頁面中事件的觸發(fā)過程[3],但I(xiàn)E 和Netscape 開發(fā)團隊提出了兩種完全不同類型的事件流。IE 提出的事件流是事件冒泡,形容事件像水中的魚類吐氣泡一樣往上冒,直到頂端,即當(dāng)頁面中某個特定目標(biāo)元素事件觸發(fā),事件會一直沿著包含關(guān)系往上傳遞(DOM樹上觸發(fā)事件的當(dāng)前結(jié)點逐級向上傳至根節(jié)點),事件冒泡的特點是從某特定事件目標(biāo)開始到不確定的事件目標(biāo)結(jié)束,如圖1 所示。而Netscape 提出的是另一種事件流——事件捕獲,它與事件冒泡的傳播順序基本上完全相反,強調(diào)事件到達(dá)特定目標(biāo)節(jié)點之前就應(yīng)該對該事件進(jìn)行捕獲,即document 最先獲取事件,然后事件沿DOM 樹依次向下傳,直到特定目標(biāo)節(jié)點,如圖2 所示[2]。需要注意的是,現(xiàn)代瀏覽器盡管都支持事件冒泡,但實現(xiàn)細(xì)節(jié)略有差別,有些瀏覽器在事件冒泡過程中會從body 跳過html,直接到document,而有些瀏覽器則一直冒泡到window 對象,如在IE5.5、IE6 和主流瀏覽器中,事件冒泡過程分別為div →body →document、div →body →html →document 和div →body →html →document →window?,F(xiàn)代瀏覽器基本都支持事件捕獲,但由于歷史原因,基本都是從window 對象開始捕獲事件,而非按DOM2 級事件規(guī)范要求的“事件應(yīng)從document 對象開始傳播”。由于舊版瀏覽器(如IE9 以前版本)不支持事件捕獲,因此在開發(fā)中建議優(yōu)先使用事件冒泡,如有特殊需要再選擇使用事件捕獲。

圖1 事件冒泡模型

圖2 事件捕獲模型

下面以一個簡單的例子來展示事件冒泡和事件捕獲的具體過程,html 和JavaScript 主要代碼如下:

wrapper

container

分別為wrapper、container 和btn 三個div 元素注冊了click 單擊事件,當(dāng)點擊了btn 元素后,從圖3 可以看到這三個元素是按事件冒泡接收事件,即btn →container →wrapper,這是因為函數(shù)addEventListener(eventType,function,useCapture)三個參數(shù)中,第一個參數(shù)表示觸發(fā)的事件類型,此處用了click;第二個參數(shù)是該事件觸發(fā)后的回調(diào)函數(shù),可處理事件觸發(fā)后的具體操作;第三個參數(shù)是布爾值,用來開啟或關(guān)閉捕獲模式,true 為捕獲模式,false 為冒泡模式,如果不傳該參數(shù)的話,就采用默認(rèn)的冒泡模式,上例中就是采用默認(rèn)的冒泡模式。當(dāng)將上例中addEventListener()函數(shù)都添加第三個參數(shù)值true 時,則三個元素就會按事件捕獲來接收事件,即wrapper →container →btn。

圖3 事件冒泡示例

3 DOM 事件流

不同級別的DOM采用DOM事件處理方式也不同。DOM的級別一共分為4 級,即DOM0 級、DOM1 級、DOM2 級和DOM3 級。由于DOM1 級標(biāo)準(zhǔn)中沒有定義事件相關(guān)的內(nèi)容,所以不存在1 級DOM事件模型,因此,DOM事件只有3 個級別,即DOM0 級事件、DOM2 級事件和DOM3 級事件[4-5]。

由于DOM0 級事件中存在冒泡和捕獲兩種截然不同的事件流模型,引發(fā)了大眾對web 事件流的猜測。因此,ECMAScript 對事件流在DOM2 中進(jìn)行了新的規(guī)范,規(guī)定事件流順序包含了“事件捕獲、處于目標(biāo)和事件冒泡”三個階段,融入了冒泡和捕獲兩種事件模型,如圖4 所示。其中事件捕獲階段提供了攔截事件的機會,處于目標(biāo)階段確保特定目標(biāo)接收到事件,事件冒泡階段負(fù)責(zé)對事件做出響應(yīng)。雖然在DOM2 中明確指出“在事件捕獲階段,事件不會接觸到事件目標(biāo)元素”,然而各瀏覽器廠商好像并沒有完全遵守,因此在事件捕獲階段和事件冒泡階段均有在事件目標(biāo)上進(jìn)行事件處理的機會。

圖4 DOM事件流模型

隨著網(wǎng)頁的運行環(huán)境越來越復(fù)雜、用戶對網(wǎng)頁的功能需求越來越大,DOM3 級事件應(yīng)運而生,DOM3 級事件在DOM2 級事件的基礎(chǔ)上重新對事件進(jìn)行了規(guī)整分類,大致可分為UI 事件、焦點事件、鼠標(biāo)事件、滾輪事件、文本事件、鍵盤事件、合成事件和變動事件等幾種。新增的DOM3 級事件主要是面對其他各種運行環(huán)境的事件,比如用于檢測移動端設(shè)備屏幕是否發(fā)生旋轉(zhuǎn),用戶是否觸摸了屏幕、是否在屏幕上滑動、是否在屏幕上畫手勢(如屏幕鎖)等觸摸或手勢事件,還有智能電視遙控器的按鍵事件等等。DOM3 事件主要是對以往的事件進(jìn)行了規(guī)劃和增加了一些面對多場景的事件類型,依然會按照事件的基本運行機制來運行,仍然需要通過事件處理程序來處理事件。

4 默認(rèn)事件與阻止事件傳播

在項目開發(fā)過程中,有時候會遇到對元素觸發(fā)事件后運行結(jié)果并沒有預(yù)期效果的情況,這個時候需要考慮到該元素的默認(rèn)事件的問題,在頁面中,所有元素都可以觸發(fā)事件,但是有些特殊元素會先觸發(fā)自身的默認(rèn)事件。比如a 標(biāo)簽,在頁面中a 標(biāo)簽的默認(rèn)事件動作是跳轉(zhuǎn)鏈接,當(dāng)點擊該元素時,頁面將會跳轉(zhuǎn)到a 標(biāo)簽href 屬性設(shè)置的那個網(wǎng)址上,如果想要阻止這種情況發(fā)生,就需要使用preventDefault()函數(shù),這個函數(shù)可以通過事件對象調(diào)用,在事件觸發(fā)時,可以利用該事件的事件對象執(zhí)行preventDefault()函數(shù)來阻止元素的默認(rèn)事件[6],然后去執(zhí)行其他代碼,示例代碼如下:

點擊我

除了默認(rèn)事件會影響代碼的運行效果外,事件的傳播也會對實現(xiàn)某些功能產(chǎn)生很大的干擾。比如現(xiàn)有一個列表,列表中每個列表項都綁定了一個事件,當(dāng)用戶鼠標(biāo)點擊該列表項時,會展開一個詳情框,顯示該列表項的數(shù)據(jù)詳情;同時,該列表項里面還包含了一個編輯按鈕,當(dāng)用戶點擊了這個按鈕的時候,當(dāng)前的列表項的文字內(nèi)容變得可修改。以冒泡事件傳播方式為例,如果在沒有阻止事件冒泡傳播的情況下,當(dāng)點擊了列表項中的那個編輯按鈕,不但列表項的內(nèi)容可以被修改,列表項的詳情框也會被展開,因為當(dāng)點擊按鈕后,按鈕觸發(fā)該事件后,事件會繼續(xù)沿著父容器向外傳播,當(dāng)傳播到包含該按鈕的列表項時,列表項也觸發(fā)了該事件。這就是很糟糕的用戶體驗了,但是通過使用阻止事件傳播就可以解決這個問題。無論是事件冒泡還是事件捕獲,都可以使用stopPropaga tion()來阻止事件的傳播,該函數(shù)與默認(rèn)事件的函數(shù)獲取方式相同,示例代碼如下:

  • item1

  • 選取我院2017年12月—2018年5月期間收治的甲狀腺CNB患者84例,且84例患者均在我院進(jìn)行了手術(shù)。84例CNB患者共87個結(jié)節(jié),其中男性16例,女性68例,年齡24~73歲,平均(42.65±5.27)歲。其中3個患者進(jìn)行2個結(jié)節(jié)穿刺,81個患者進(jìn)行1個結(jié)節(jié)穿刺。術(shù)前均進(jìn)行血常規(guī)、血凝四項、傳染病三項、乙肝五項檢查。

    item2

  • item3

代碼執(zhí)行后的效果如圖5 所示。

圖5 示例效果

阻止默認(rèn)事件的函數(shù)preventDefault()和阻止事件傳播的函數(shù)stopPropagation()是符合w3c 標(biāo)準(zhǔn)的,適用于大部分瀏覽器。但是面向舊版本的IE瀏覽器時,阻止默認(rèn)事件和阻止事件傳播則需分別使用window.event.returnValue = false 和window.event.cancelBubble = true。

5 事件處理程序

事件處理程序是指用來響應(yīng)某個事件的JavaScript 代碼片段,一般封裝成一個函數(shù),事件被觸發(fā)時,就會調(diào)用執(zhí)行這一代碼段,添加事件處理程序的方式有4 種,分別是HTML 事件處理程序、DOM0 級事件處理程序、DOM2 級事件處理程序、IE 事件處理程序。

5.1 HTML 事件處理程序

最簡單最直接的方式就是HTML 事件處理程序,可以直接在html 元素上通過添加事件屬性名,然后將要執(zhí)行的具體動作設(shè)置為該屬性的值即可,也可以通過在頁面其他地方定義腳本函數(shù)的方式來實現(xiàn),例如:。但是不能在屬性值中使用未轉(zhuǎn)義的HTML 實體字符,如不能直接使用<或>,要用相應(yīng)的實體符號<和>來替代。除此之外,HTML 事件處理程序也可以移除事件處理程序,只需將事件處理程序的屬性值設(shè)置為null 即可,但是這種方式和不綁定事件處理程序沒有什么差異,所以實用性不大。

5.2 DOM0 級事件處理程序

由于HTML 方式存在HTML 代碼與JS 代碼沒完全分離、擴展事件處理程序的作用鏈域在不同瀏覽器可能會有不同結(jié)果、時差問題和代碼緊耦合等諸多缺點,導(dǎo)致使用起來非常糟糕,而DOM0 級事件處理程序則可以避免這些問題。DOM0 級事件處理程序是使用JavaScript 指定事件處理程序的方式。在給元素綁定事件處理處理程序之前,需先獲取一個要操作的對象的引用,再將一個函數(shù)直接賦值給一個事件處理程序?qū)傩訹7],且所有的事件名都是采用小寫的,并以on 開頭,后接具體動作的事件程序名稱,示例代碼如下:

var btn = document.querySelector ('#btn'); // 先取得該對象的引用

btn.onclick = function (){ // 給引用的對象的事件屬性賦值一個匿名函數(shù),也可以是非匿名函數(shù)

alert('我是按鈕')

}

由于DOM0 級方式綁定事件處理程序使用方式簡單,并且JavaScript 和HTML 有較好的耦合度,即使html 的元素修改了,只要指定的id 不變,就能獲取到該元素,就可以使用該事件程序。如果需要移除該事件程序,則只需將事件屬性值設(shè)為null 即可,例如:btn.onclick=null。

5.3 DOM2 級事件處理程序

由于DOM1 級標(biāo)準(zhǔn)中沒有定義事件相關(guān)的內(nèi)容,所以也不存在DOM1 級事件程序,而是直接到DOM2 級事件處理程序,而這種事件處理程序在上文中已有所介紹,可分別通過addEventListener()和removeEventListener()函數(shù)實現(xiàn)DOM2 級事件程序的綁定和移除,這兩個函數(shù)都帶有三個參數(shù),且含義相同。但要注意的是,可以同時添加多個DOM2級事件處理程序,并會按添加的順序觸發(fā),這與DOM0 級事件會發(fā)生覆蓋具有完全不同的表現(xiàn),另外,DOM0 和DOM2 也可以共存,并不會互相覆蓋;第一個表示事件名的參數(shù)不再像DOM0 級那樣以on 開頭了,而是直接使用on 后面的具體動作的事件程序名稱;第二個表示處理事件的回調(diào)函數(shù),該可以是個匿名函數(shù),但是如果綁定事件時使用了匿名函數(shù)則無法將其移除[8]。

5.4 IE 事件處理程序

IE 瀏覽器可以正常使用DOM0 級事件處理程序,但是大部分IE 版本卻不支持DOM2 級事件處理程序,不過IE 提供了兩個與DOM2 級事件處理程序類似的函數(shù),即attachEvent()和detachEvent()[9-10]。attachEvent()函數(shù)為目標(biāo)元素提供事件程序綁定,該函數(shù)接收兩個參數(shù),第一個參數(shù)是事件名,但這里的事件名與DOM0 級的事件名是一致的,即以on 開頭的,例如:‘onclick’;而第二個參數(shù)是處理事件的回調(diào)函數(shù),需要注意的是,從IE11 起,attachEvent()函數(shù)就無法使用了。而detachEvent()函數(shù)是用于移除事件程序的,該函數(shù)需要的參數(shù)與attachEvent()函數(shù)的參數(shù)一致。在網(wǎng)頁運行環(huán)境不確定情況下,可通過if 語句判斷當(dāng)前瀏覽器是否支持該事件程序來選擇函數(shù),下面是事件綁定(事件移除過程類似)示例代碼:

var target = document.querySelector('#target');

var handler = function(){

console.log('DOM2 級事件處理程序')

}

//檢測是否支持DOM2 級事件處理程序

if(target.addEventListener){

target.addEventListener ('click',handler,false)

}else{

target.attachEvent("onclick", handler);

}

6 性能優(yōu)化

在網(wǎng)頁中,每添加一個事件處理程序,瀏覽器就會開辟一塊內(nèi)存空間。因為每綁定一個事件處理程序都需要綁定一個事件處理的函數(shù),而在js的定義中,函數(shù)是屬于對象的,每新建一個對象,瀏覽器都要開辟一塊內(nèi)存給這個對象存儲數(shù)據(jù)。那么隨著網(wǎng)頁的內(nèi)容越來越多,越來越復(fù)雜,頁面的綁定的事件程序就會越來越多,使用的內(nèi)存也會越來越多,就會導(dǎo)致網(wǎng)頁的運行速度變慢,因此就需要對網(wǎng)頁的性能進(jìn)行進(jìn)一步的優(yōu)化。

事件移除和事件委托就是常用的性能優(yōu)化手段。通過調(diào)用移除事件處理函數(shù)可以釋放給元素綁定一個事件處理程序在瀏覽器中開辟的內(nèi)存空間。事件委托就是一個針對頁面由于綁定事件處理程序過多而導(dǎo)致網(wǎng)頁內(nèi)存占用過大問題提出的一個性能優(yōu)化解決方案,主要是利用事件流中的冒泡傳播方式,在頂層的父元素上綁定一個事件處理程序,專門處理該元素下產(chǎn)生的事件。如上文阻止事件傳播的例子中給列表中的每個列表項都添加了一個事件處理程序,如果列表項很多,就會導(dǎo)致頁面的內(nèi)存消耗過大,性能比較糟糕,可以通過事件委托來優(yōu)化這個問題。

猜你喜歡
列表瀏覽器網(wǎng)頁
學(xué)習(xí)運用列表法
基于HTML5與CSS3的網(wǎng)頁設(shè)計技術(shù)研究
擴列吧
微軟發(fā)布新Edge瀏覽器預(yù)覽版下載換裝Chrome內(nèi)核
反瀏覽器指紋追蹤
基于CSS的網(wǎng)頁導(dǎo)航欄的設(shè)計
基于HTML5靜態(tài)網(wǎng)頁設(shè)計
基于URL和網(wǎng)頁類型的網(wǎng)頁信息采集研究
列表畫樹狀圖各有所長
2011年《小說月刊》轉(zhuǎn)載列表
方城县| 丰县| 雅安市| 卓尼县| 小金县| 天长市| 东光县| 临武县| 龙游县| 民丰县| 万山特区| 尉氏县| 灵石县| 扶沟县| 太原市| 宝清县| 垫江县| 剑川县| 马边| 比如县| 宕昌县| 湟源县| 若尔盖县| 景泰县| 康乐县| 嵩明县| 日照市| 礼泉县| 濮阳市| 浮梁县| 林口县| 合阳县| 姜堰市| 宁强县| 巩义市| 扎赉特旗| 大理市| 通道| 彭水| 阿瓦提县| 涿州市|