Dom事件以及傳播機(jī)制

dom事件

  • 1.什么是事件?
    事件就是一件事情或者行為(對(duì)于元素來說他的很多事件都是天生自帶)只要我們?nèi)ゲ僮鬟@個(gè)元素就會(huì)觸發(fā)事件。
    事件就是元素天生自帶的行為,我們操作元素就會(huì)觸發(fā)相關(guān)的事件行為
  • 2.事件綁定:給元素天生自帶的事件行為綁定方法,當(dāng)事件觸發(fā)會(huì)把對(duì)應(yīng)的方法執(zhí)行
  • 3.元素天生自帶的事件

鼠標(biāo)事件
click:點(diǎn)擊(pc端是點(diǎn)擊惨奕,移動(dòng)端的click代表單擊,并且使用click會(huì)有300ms的延遲)
dblclick:雙擊
mouseover:鼠標(biāo)經(jīng)過
mouseout:鼠標(biāo)移出
mouseenter:鼠標(biāo)進(jìn)入
mouseleave:鼠標(biāo)離開
mousemove:鼠標(biāo)移動(dòng)
mousedown:鼠標(biāo)按下(鼠標(biāo)左右鍵都起作用他是按下即觸發(fā)竭钝,click是按下抬起才出發(fā)梨撞,而且是先把down和up先觸發(fā)雹洗,click才觸發(fā))
mouseup:鼠標(biāo)抬起
mousewheel:鼠標(biāo)滾輪滾動(dòng)
鍵盤事件
keydown:鍵盤按下
keyup:鍵盤抬起
keypress:和keydown類似只不過keydown返回的是鍵盤碼。keypress返回的是ASCII碼值
[圖片上傳失敗...(image-51ec19-1570785135646)]

input:由于pc有實(shí)體物理鍵盤聋袋,可以監(jiān)聽到鍵盤的按下和抬起,但是移動(dòng)端是虛擬的鍵盤穴吹,所以keydown和keyup在大部分手機(jī)上都沒有幽勒,我們使用input事件統(tǒng)一代替他們(內(nèi)容改變事件)

表單元素常用的事件
focus:獲取焦點(diǎn)
blur:失去焦點(diǎn)
change:內(nèi)容改變
其他常用事件
load:加載完成
unload:
beforeunload:
scroll:滾動(dòng)條滾動(dòng)事件
resize:大小改變事件window.onresize=function(){}當(dāng)瀏覽器窗口大小發(fā)生改變會(huì)觸發(fā)這個(gè)事件執(zhí)行對(duì)應(yīng)的事情。
readystatechange:ajax狀態(tài)改變
移動(dòng)端手指事件
gesture:多指操作
touchstart:手指按下
touchmove:手指移動(dòng)
touchend:手指離開
touchcancel:因?yàn)橐馔馇闆r導(dǎo)致手指操作取消
gesturestart:多指按下
gesturechange:多指改變
gestureend:手指離開
h5中的audio港令、video音頻事件
canplay啥容;可以播放(播放過程中可能出現(xiàn)由于資源沒有加載完成導(dǎo)致卡頓
canplaythrough:資源加載完成可以正常無障礙播放

事件綁定

DOM0級(jí)事件綁定
[element].onxxx=function(){};


DOM2級(jí)事件綁定
[element].addEventListener('xxx',function(){},false);
[element].attachEvent('onxxx',function(){});[ie6-8];


給元素的事件行為綁定方法,當(dāng)行為觸發(fā)的時(shí)候?yàn)g覽器會(huì)把綁定的方法執(zhí)行
1.方法中的this:當(dāng)前操作的元素(除非自己改動(dòng)this顷霹,比如箭頭函數(shù)咪惠,或者bind)
2.事件綁定屬于異步操作,綁定的時(shí)候方法沒有執(zhí)行淋淀,還是創(chuàng)建方法的階段呢遥昧,當(dāng)行為觸發(fā)瀏覽器才會(huì)把方法執(zhí)行。(當(dāng)然也有變態(tài)的執(zhí)行方式:bo.onclick(),這樣執(zhí)行僅僅是把它當(dāng)做一個(gè)變量和函數(shù)執(zhí)行朵纷,和事件沒啥關(guān)系炭臭。)
3.瀏覽器不僅把這個(gè)方法執(zhí)行了,還記錄了當(dāng)前本次操作的相關(guān)信息(如果是鼠標(biāo)點(diǎn)擊袍辞,瀏覽器記錄點(diǎn)擊的位置鞋仍,點(diǎn)的是誰(shuí)等信息),把這些信息都存儲(chǔ)到一個(gè)對(duì)象中(這個(gè)對(duì)象就是實(shí)踐對(duì)象:記錄當(dāng)前本次操作信息的對(duì)象)搅吁;更重要的是標(biāo)準(zhǔn)瀏覽器會(huì)把這個(gè)對(duì)象(堆內(nèi)存)傳遞給執(zhí)行的方法威创。我們可以在方法中通過形參或者實(shí)參集合等方式受到傳遞的事件對(duì)象信息;

目的:給當(dāng)前元素的某個(gè)事件綁定方法不管是基于dom0還是dom2都是為了觸發(fā)元素的相關(guān)行為的時(shí)候能做點(diǎn)事情也就是把綁定的方法執(zhí)行谎懦;不僅把方法執(zhí)行了而且瀏覽器還給方法傳遞了一個(gè)實(shí)參信息值===》這個(gè)值就是事件對(duì)象ev
目的:事件對(duì)象中記錄了很多屬性名和屬性值肚豺,這些信息中包含了當(dāng)前操作的基礎(chǔ)信息,例如鼠標(biāo)點(diǎn)擊位置的x/y軸坐標(biāo)界拦,鼠標(biāo)點(diǎn)擊的是誰(shuí)(事件源)等信息

    box.onclick=function(ev){//定義一個(gè)形參ev用來接收方法執(zhí)行的時(shí)候详炬,瀏覽器傳遞的信息值(事件對(duì)象mouseevent鼠標(biāo)事件對(duì)象,keyboardevent鍵盤事件對(duì)象寞奸,event普通事件對(duì)象呛谜。。)
    //目的:事件對(duì)象中記錄了很多屬性名和屬性值枪萄,這些信息中包含了當(dāng)前操作的基礎(chǔ)信息隐岛,例如鼠標(biāo)點(diǎn)擊位置的x/y軸坐標(biāo),鼠標(biāo)點(diǎn)擊的是誰(shuí)(事件源)等信息
   
    console.log(ev);}

ev.target:事件源(操作的是哪個(gè)元素) ev.srcElement;低版本瀏覽器
ev.clientX/ev.clientY:當(dāng)前鼠標(biāo)觸發(fā)點(diǎn)距離當(dāng)前窗口左上角的x/y軸坐標(biāo)
ev.pageX/ev.pageY:當(dāng)前鼠標(biāo)觸發(fā)點(diǎn)距離body(第一屏)左上角的x/y軸坐標(biāo)瓷翻。
ev.preventDefault():阻止默認(rèn)行為
ev.stopPropagation():阻止事件的冒泡傳播
ev.cancelBubble = true;//=>低版本阻止冒泡傳播
ev.type:當(dāng)前事件類型

[圖片上傳失敗...(image-12f843-1570785135646)]

   [用到其中的幾個(gè)屬性聚凹,需要處理兼容]
    box割坠。onclick=function(ev){
    ev=ev||window.event;
    let target=ev.target||ev.srcElement,
    pageY=ev.pageY||(ev.clientY+(document.documentElement.scrollTop||document.body.scrollTop))};
    [很多地方都用到這些屬性,而且用的多]
    function handleEvent(ev){
   if(window.event&&!ev){//低版本瀏覽器妒牙,我們需要處理的不僅僅是把ev賦值彼哼,還要把高版本中有低版本沒有的屬性給ev加上
   ev=window.event;
   ev.target=ev.srcElement;
   ev.pageX=ev.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft;
   ev.pageY=ev.clientY+(document.documentElement.scrollTop||document.body.scrollTop;
   ev.which=ev.keyCode;
   ev.preventDefault=function(){
   ev.return=false;
 }
ev.stopPropagation=function(){
ev.cancelBubble=true
}
   }
    return ev;
    }
    box.onclick=function(ev){
    ev.handleEvent(ev);
    let target=ev.target;
    }

keyboardEvent
ev.code:當(dāng)前按鍵“keyE”
ev.key:當(dāng)前按鍵'e'
ev.which/ev.keycode:當(dāng)前按鍵的鍵盤碼69


常用的鍵盤碼
左 - 上 - 右 - 下 :37-38-39-40
Backspace刪除鍵:18
Enter:13
Space:32
Delete:46

Shift:16
Alt:18
Ctrl:17
Esc:27
F1-F12:112-123
0-9:48-57
a-z:小寫字母

[圖片上傳失敗...(image-347bfa-1570785135646)]

box.onclick = function(ev){
    if(!ev){
    //兼容思想:低版本沒有的屬性,我們手動(dòng)設(shè)置一些:按照自己有的先獲取到值湘今,然后賦值給標(biāo)準(zhǔn)對(duì)應(yīng)的新屬性(經(jīng)過判斷處理后敢朱,低版本中也有target/pageX/pageY這些屬性),后期在使用的時(shí)候摩瞎,直接按照高版本的使用即可
        ev = window.event;      
        console.log(ev.srcElement); //=>ev.srcElement是獲取事件源(標(biāo)準(zhǔn)瀏覽器使用的是ev.target)
        console.log(ev.ev.pageX); //=>低版本瀏覽器的事件對(duì)象中不存在pageX/pageY
        ev.target = ev.srcElement拴签;
        ev.pageX = ev.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft)
        ev.pageY = ev.clientX+(document.documentElement.scrollTop||document.body.scrollTop)
        ev.which = ev.keyCode;
        //ev.preventDefault  ev.stopPropagation 低版本不存在
        ev.preventDefault = function(){
            ev.returnValue = false; //低版本阻止默認(rèn)行為
        }
        ev.stopPropagation = function(){
            ev.cancelBubble= true; //低版本阻止冒泡傳播
        }
         
    }
    //=>直接按照高版本的規(guī)則使用
    console.log(ev.target,ev.which);
}
//兼容處理方法二
box.onclick = function(){
        //用到誰(shuí),給誰(shuí)處理兼容
        ev=ev || window.event;
        var target = ev.target || ev.srcElement;
        ev.preventDefault()?ev.preventDefault()():ev.returnValue=false;
    }

事件的默認(rèn)行為

事件本身就是天生就有的旗们,某些事件觸發(fā)即使你沒有綁定方法也會(huì)存在一些效果蚓哩,這些默認(rèn)的效果就是事件的默認(rèn)行為
1.點(diǎn)擊A實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)
2.錨點(diǎn)定位(href=“元素的ID”),點(diǎn)擊的時(shí)候url中設(shè)置對(duì)應(yīng)的hash值(#xxx)上渴,頁(yè)面加載完成后會(huì)定位到ID和hash值相同的盒子位置岸梨。真實(shí)項(xiàng)目中就是一個(gè)普通按鈕,不想實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)或者錨點(diǎn)定位稠氮。此時(shí)我們需要阻止點(diǎn)擊A的時(shí)候的默認(rèn)行為盛嘿。
結(jié)構(gòu)上阻止:href="JavaScript:;"或者void(0),null;undefined;
js方法阻止:

link.onclick=function(ev){
    ev=ev||window.event;
    ev.preventDefault?ev.preventDefault():ev.returnValue=false;
    }
 或者link.onclick=function(){
    return false;
    //原理:點(diǎn)擊A的時(shí)候首先觸發(fā)的是click其次才會(huì)觸發(fā)它的默認(rèn)行為,我們?cè)赾lick中返回false其意思是阻止下一步繼續(xù)操作括袒。
    }

基于hash值可以實(shí)現(xiàn)spa單頁(yè)面應(yīng)用
input標(biāo)簽也有自己的默認(rèn)行為
1.輸入內(nèi)容可以呈現(xiàn)到文本框中
2.輸入內(nèi)容的時(shí)候會(huì)把之前輸入的一些信息呈現(xiàn)出來次兆,并不是所有瀏覽器和所有情況下都有

    //真實(shí)項(xiàng)目中我們根據(jù)需求可能會(huì)組織文本框輸入內(nèi)容,此時(shí)其實(shí)就是阻止他的默認(rèn)行為
userInp.onkeydown=userInp.onkeyup=function(ev){
let val=this.value.trim(),
len=val.length;
if(len>10){
this.value=val.substr(0,10);超過十位的截掉
有值的鍵是不允許輸入的del/back-space/space/shift/ctrl/alt/tab...
}
}

submit按鈕也存在默認(rèn)行為
1.點(diǎn)擊按鈕頁(yè)面會(huì)刷新

<from action='wangzhi'><input type='submit'></from>

事件的傳播機(jī)制

冒泡傳播:觸發(fā)當(dāng)前元素的某一個(gè)事件(點(diǎn)擊事件)行為不僅當(dāng)前元素事件行為觸發(fā)锹锰,而且其祖先元素的相關(guān)事件行為也會(huì)一次被觸發(fā)芥炭,這種機(jī)制就是事件的冒泡傳播機(jī)制

  • 捕獲階段:點(diǎn)擊inner的時(shí)候首先會(huì)從最外層開始向內(nèi)查找的(找到操作的事件源)恃慧,查找的目的是構(gòu)建出冒泡傳播階段需要傳播的路線(查找就是按照HTML層級(jí)結(jié)構(gòu)找的)
  • 目標(biāo)階段:把事件源的相關(guān)操作行為觸發(fā)(如果綁定了方法則把方法執(zhí)行)
  • 冒泡傳播:按照捕獲階段規(guī)劃的路線自內(nèi)而外把當(dāng)前事件源的祖先元素的相關(guān)事件行為一次觸發(fā)(如果某一個(gè)祖先元素事件行為綁定了方法园蝠,則把方法執(zhí)行,沒綁定方法痢士,行為觸發(fā)了彪薛,什么都不做,繼續(xù)向上傳播即可)
    [圖片上傳失敗...(image-a72b79-1570785135646)]
  xxx.onxxx=function(){};dom0事件綁定怠蹂,給元素的事件行為綁定方法這些都是在當(dāng)前元素事件行為的冒泡階段或者目標(biāo)階段執(zhí)行的
    xxx.addEventListener('xxx',function(){},false)第三個(gè)參數(shù)false也是控制綁定的方法在事件傳播的冒泡階段或者目標(biāo)階段執(zhí)行善延,只有第三個(gè)參數(shù)為true才代表讓當(dāng)前方法在事件傳播的冒泡階段或者目標(biāo)階段執(zhí)行
    

不同瀏覽器對(duì)最外層祖先元素的定義是不一樣的
谷歌:window->document->html->body...
IE高:window->html->body...
IE低:html->body...
關(guān)于事件對(duì)象的一些理解
1.事件對(duì)象是用來存儲(chǔ)當(dāng)前本次操作的相關(guān)信息,和操作有關(guān)城侧,和元素?zé)o必然關(guān)聯(lián)易遣,
2.當(dāng)我們基于鼠標(biāo)或者鍵盤等操作的時(shí)候,瀏覽器會(huì)把本次操作的信息存儲(chǔ)起來(標(biāo)準(zhǔn)瀏覽器存儲(chǔ)到默認(rèn)的內(nèi)存中(自己找不到)嫌佑,IE低版本存儲(chǔ)到window.event中了)存儲(chǔ)的值是一個(gè)對(duì)象(堆內(nèi)存);操作肯定會(huì)觸發(fā)元素的某個(gè)行為豆茫,綁定的方法侨歉,執(zhí)行此時(shí)標(biāo)準(zhǔn)瀏覽器會(huì)把之前存儲(chǔ)的對(duì)象(準(zhǔn)確來說是堆內(nèi)存地址)當(dāng)做實(shí)參傳遞給每一個(gè)執(zhí)行方法,所以操作一次即使更多方法中都有ev揩魂,但是存儲(chǔ)的值都是一個(gè)(本次操作信息的對(duì)象而已)
mouseenter和mouseover區(qū)別
over屬于滑過覆蓋事件幽邓,從父元素進(jìn)入到子元素屬于離開了父元素,會(huì)觸發(fā)父元素的out觸發(fā)子元素的over
enter屬于進(jìn)入火脉,從父元素進(jìn)入子元素牵舵,并不算離開父元素,不會(huì)觸發(fā)父元素的leave觸發(fā)子元素的enter忘分。
enter和leave阻止了事件的冒泡傳播棋枕,而over和out還存在冒泡傳播白修。
所以對(duì)于父元素嵌套子元素這種情況使用over會(huì)發(fā)生很多不愿意操作的事情妒峦,此時(shí)我們使用enter會(huì)更簡(jiǎn)單,操作方便兵睛,所以真實(shí)項(xiàng)目中用enter的使用會(huì)比over多肯骇。
[圖片上傳失敗...(image-82f92c-1570785135646)]

事件委托

利用事件的冒泡傳播機(jī)制,如果一個(gè)容器的后代元素中很多元素的點(diǎn)擊行為都要做一些處理此時(shí)我們不需要像以前一樣一個(gè)一個(gè)獲取然后綁定了祖很,我們只需要給容器的click綁定方法即可笛丙,這樣不管點(diǎn)擊是哪個(gè)后代元素,都會(huì)根據(jù)冒泡傳播的傳遞機(jī)制假颇,把容器的click行為觸發(fā)胚鸯,把對(duì)應(yīng)的方法執(zhí)行,根據(jù)事件源我們可以知道點(diǎn)擊的是誰(shuí)從而做不同的事情

初步了解JS中事件綁定的方式

DOM0事件綁定

oBox.onclick=function(e){
    //=>this:oBox
    e=e||window.event;
}
oBox.onmouseenter=function(){}
...

DOM2事件綁定

//=>標(biāo)準(zhǔn)瀏覽器
oBox.addEventListener('click',function(e){
    //=>this:oBox
    //=>e:事件對(duì)象
},false);
//=>false:讓當(dāng)前綁定的方法在冒泡傳播階段執(zhí)行(一般都用FALSE)
//=>true:讓當(dāng)前綁定的方法在捕獲階段執(zhí)行(一般不用)

//=>IE6~8
oBox.attachEvent('onclick',function(e){
    //=>e:事件對(duì)象笨鸡,不同于DOM0事件綁定姜钳,使用attachEvent綁定方法,當(dāng)事件觸發(fā)方法執(zhí)行的時(shí)候形耗,瀏覽器也會(huì)把事件對(duì)象當(dāng)做實(shí)參傳遞給函數(shù)(傳遞的值和window.event是相同的)哥桥,所以IE6~8下獲取的事件對(duì)象對(duì)于:pageX\pageY\target...依然沒有,還是存在兼容性(事件對(duì)象兼容處理在DOM2中依然存在)
});
//=>此時(shí)綁定的方法都是在冒泡傳播階段執(zhí)行

有DOM0和DOM2事件綁定激涤,那么DOM1事件綁定呢拟糕?
因?yàn)樵贒OM第一代升級(jí)迭代的時(shí)候,DOM元素的事件綁定方式依然沿用的是DOM0代綁定的方式倦踢,在此版本DOM中送滞,事件綁定沒有升級(jí)處理

DOM0事件綁定和DOM2事件綁定的區(qū)別

DOM0事件綁定的原理
1、給當(dāng)前元素對(duì)象的某一個(gè)私有屬性(onxxx這樣的私有屬性)賦值的過程(之前屬性默認(rèn)值是null辱挥,如果我們給賦值一個(gè)函數(shù)累澡,相當(dāng)于綁定了一個(gè)方法)
2、當(dāng)我們賦值成功(賦值一個(gè)函數(shù))般贼,此時(shí)瀏覽器會(huì)把DOM元素和賦值的函數(shù)建立關(guān)聯(lián)愧哟,以及建立DOM元素行為操作的監(jiān)聽奥吩,當(dāng)某一個(gè)行為被用戶觸發(fā),瀏覽器會(huì)把相關(guān)行為賦值的函數(shù)執(zhí)行

特點(diǎn):

//=>1蕊梧、只有DOM元素天生擁有這個(gè)私有屬性(onxxx事件私有屬性)霞赫,我們賦值的方法才叫做事件綁定,否則屬于給當(dāng)前元素設(shè)置一個(gè)自定義屬性而已
document.body.onclick=function(){}//->事件綁定
/*
 * 手動(dòng)點(diǎn)擊頁(yè)面中的BODY觸發(fā)方法執(zhí)行
 * document.body.onclick() 這樣執(zhí)行也可以
*/

document.body.onzhufeng=function(){}//->設(shè)置自定義屬性
/*
 * 只能document.body.onzhufeng()這樣執(zhí)行
 */

//=>2肥矢、移除事件綁定的時(shí)候端衰,我們只需要賦值為null即可
document.body.onclick=null;

//=>3、在DOM0事件綁定中甘改,只能給當(dāng)前元素的某一個(gè)事件行為(某一個(gè)事件私有屬性)綁定一個(gè)方法旅东,綁定多個(gè)方法,最后一次綁定的會(huì)把之前綁定的都替換掉
document.body.onclick=function(){
    console.log(1);
}
document.body.onclick=function(){
    console.log(2);
}
//=>點(diǎn)擊BODY只能輸出2十艾,因?yàn)榈诙钨x值的函數(shù)把第一次賦值的函數(shù)給替換了

DOM2事件綁定的原理
1抵代、我們DOM2事件綁定使用的addEventListener/attachEvent都是在EventTarget這個(gè)內(nèi)置類的原型上定義的,我們調(diào)取使用的時(shí)候忘嫉,首先通過原型鏈找到這個(gè)方法荤牍,然后執(zhí)行完成事件綁定的效果

2、瀏覽器首先會(huì)給當(dāng)前元素的某一個(gè)事件行為開辟一個(gè)事件池(事件隊(duì)列)[其實(shí)是瀏覽器有一個(gè)統(tǒng)一的事件池庆冕,我們每個(gè)元素的某個(gè)行為綁定的方法都放在這個(gè)事件池中康吵,只是通過相關(guān)的標(biāo)識(shí)來區(qū)分的],當(dāng)我們通過addEventListener做事件監(jiān)聽的時(shí)候访递,會(huì)把綁定的方法存放在事件池中

3晦嵌、當(dāng)元素的某一個(gè)行為觸發(fā),瀏覽器會(huì)到對(duì)應(yīng)的事件池中拷姿,把當(dāng)前存放在事件池中的所有方法惭载,依次按照存放的先后順序執(zhí)行

特點(diǎn):

//=>1、所有DOM0支持的事件行為跌前,DOM2都可以使用棕兼,不僅如此,DOM2還支持一些DOM0沒有的事件行為:DOMContentLoaded...

window.onDOMContentLoaded === undefined; //=>DOM0中沒有這個(gè)屬性

window.addEventListener('DOMContentLoaded',function(){
    //=>標(biāo)準(zhǔn)瀏覽器中兼容這個(gè)事件:當(dāng)瀏覽器中的DOM結(jié)構(gòu)加載完成抵乓,就會(huì)觸發(fā)這個(gè)事件(也會(huì)把綁定的方法執(zhí)行)
},false);

window.attachEvent('onDOMContentLoaded',function(){
    //=>IE6~8中的DOM2也不支持這個(gè)事件
});

//=>2伴挚、DOM2中可以給當(dāng)前元素的某一個(gè)事件行為綁定‘多個(gè)不同的方法’(因?yàn)榻壎ǖ乃蟹椒ǘ即娣旁谑录刂辛耍?function fn1(){
    console.log(1);
}
function fn2(){
    console.log(2);
}
function fn3(){
    console.log(3);
}
document.body.addEventListener('click',fn1,false);
document.body.addEventListener('click',fn3,false);
document.body.addEventListener('click',fn2,false);
document.body.addEventListener('click',fn3,false);//=>本次向事件池中存儲(chǔ)的時(shí)候,發(fā)現(xiàn)fn3已經(jīng)在事件池中存在了灾炭,不能再存儲(chǔ)了

//3茎芋、DOM2事件綁定的移除比較麻煩一些,需要和綁定的時(shí)候:事件類型蜈出、綁定的方法田弥、傳播階段,三個(gè)完全一致才可以移除掉
document.body.removeEventListener('click',fn2,false);

document.body.addEventListener('click',function(){
    console.log(1);
},false);

document.body.removeEventListener('click',function(){
    console.log(1);
},false);
//=>DOM2事件綁定需要我們養(yǎng)成‘未雨綢繆’的能力铡原,綁定方法的時(shí)候盡量不用匿名函數(shù)偷厦,為后期可能會(huì)把方法在事件池中移除掉做準(zhǔn)備

dom0:
box.onclick=function(){};每一個(gè)元素對(duì)象都是對(duì)應(yīng)類的實(shí)例商叹,瀏覽器天生為其設(shè)置了很多私有屬性和公有的屬性方法,而onclick就是其中的一個(gè)私有屬性(事件類私有屬性只泼,還有很多其他的事件私有屬性剖笙,)
這些屬性值默認(rèn)為null
dom0事件綁定的原理:就是給元素的某一個(gè)事件私有屬性賦值(瀏覽器會(huì)建立監(jiān)聽機(jī)會(huì),當(dāng)我們觸發(fā)元素的某個(gè)行為请唱,瀏覽器會(huì)把屬性中賦的值去執(zhí)行)
dom0事件綁定弥咪,只允許給當(dāng)前元素的某個(gè)事件行為綁定一個(gè)方法,多次綁定后面綁定的會(huì)替換前面綁定的十绑,以最后一次綁定的方法為主

dom2:
box.addEventListener('click',function(){},false)還有removeEventListener('click',function(){},false)移除聚至,(使用的方法都是EventTarget.prototype定義的),完成時(shí)間幫頂是基于事件池機(jī)制完成的本橙。
在IE低版本當(dāng)中使用的是attachEvent來處理的扳躬,box.attachEvent('onclick',function(){})移除使用的是dettachEvent

dom2事件綁定可以給當(dāng)前元素的某一個(gè)事件行為綁定“多個(gè)不同的方法”。
dom2事件綁定的兼容
谷歌vsie高版本
在一處事件綁定的時(shí)候如果移除操作發(fā)生在正要執(zhí)行的方法之前勋功,如點(diǎn)擊的時(shí)候坦报,正要執(zhí)行F8但是在執(zhí)行Fn4的時(shí)候沃恩吧fn8從是堅(jiān)持中移除了库说,谷歌下是立即移除生效狂鞋,第一次也不再執(zhí)行FN8了而IE是當(dāng)前本次不生效,下一次點(diǎn)擊才生效潜的,第一次點(diǎn)擊還是要執(zhí)行FN8的
標(biāo)準(zhǔn)vsIE低版本
標(biāo)準(zhǔn):addEventListener/removeEventListener
Ie低版本:attchEvent/dettachEvent
1.this問題:標(biāo)準(zhǔn)瀏覽器中行為觸發(fā)方法執(zhí)行方法中的this是當(dāng)前元素本身骚揍,IE低版本中this執(zhí)行了window
2.重復(fù)問題:標(biāo)準(zhǔn)瀏覽器中的是堅(jiān)持是默認(rèn)去重復(fù)的,同一個(gè)元素的同一個(gè)事件行為不能出現(xiàn)相同的綁定方法啰挪,但是IE低版本的事件池機(jī)制沒有那么完善信不,不能默認(rèn)去重,也就是可以給同個(gè)元素的同個(gè)事件綁定相同的方法了
3.順序問題:標(biāo)準(zhǔn)瀏覽器是按照向事件池中存放的順序依次執(zhí)行的亡呵,而IE低版本是亂序執(zhí)行的沒有規(guī)律
IE低版本瀏覽器出現(xiàn)的所有問題都是由于本身自帶的事件池機(jī)制不完善導(dǎo)致的

dom0和dom2事件綁定的區(qū)別
1.機(jī)制不同:
dom0采用給私有屬性賦值抽活,所以只能綁定一個(gè)方法
dom2采用的是事件池機(jī)制,能綁定多個(gè)不同的方法
2.移除的操作不同:
box.onclick=function(){};
box.onclick=null;賦值為null就移除了
box.addEventListener('click',function(){console.log(1)},false);
box.removeEventListener('click',function(){console.log(1)},false);
dom2在移除的時(shí)候必須清楚要移除哪一個(gè)方法才能在事件池中移除掉所以基于dom2做事件綁定锰什,我們要有瞻前顧后的思路下硕,也就是綁定的時(shí)候考慮一下如何移除(技巧不要綁定匿名函數(shù),都綁定實(shí)名函數(shù))
3.dom2事件綁定中增加了一些domo無法操作的事件行為汁胆,例如DOMContentLoaded事件(當(dāng)頁(yè)面中的HTML結(jié)構(gòu)加載完成就會(huì)觸發(fā)執(zhí)行)

JQ中的事件綁定
on / off:基于DOM2事件綁定實(shí)現(xiàn)事件的綁定和移除(兼容了所有的瀏覽器)
one:只綁定一次梭姓,第一次執(zhí)行完成后,會(huì)把綁定的方法移除(基于ON/OFF完成的)
click / mouseover / mouseout ...:JQ提供快捷綁定方法嫩码,但是這些方法最后都是基于ON/OFF完成的
delegate:事件委托方法(1.7版本以前用的是live方法)
bind / unbind:正常綁定
window.onload和$(document).ready()

window.onload = function () {
        //=>當(dāng)頁(yè)面中的資源都加載完成(HTML結(jié)構(gòu)加載完誉尖、CSS和JS等資源加載完成等)才會(huì)觸發(fā)執(zhí)行
    };
    // window.addEventListener('load',function(){}); //=>這樣處理也可以執(zhí)行多次了

    //=>$(document).ready(function(){})
    //原理:基于DOMContentLoaded完成的(IE中用的是onreadystatechange監(jiān)聽的,在document.readyState === "complete"時(shí)候執(zhí)行函數(shù))
    $(function () {
        //=>當(dāng)頁(yè)面中的HTML結(jié)構(gòu)加載完成就會(huì)執(zhí)行

    });

    $(function(){
        //=>基于DOM2事件綁定的铸题,所以在同一個(gè)頁(yè)面中可以執(zhí)行多次(綁定多個(gè)不同的方法)铡恕,當(dāng)結(jié)構(gòu)加載完成琢感,會(huì)依次執(zhí)行這些方法
    });

window.onload和$(document).ready()的區(qū)別

window.onload:當(dāng)瀏覽器中所有的資源內(nèi)容(DOM結(jié)構(gòu)、文本內(nèi)容探熔、圖片...)都加載完成猩谊,觸發(fā)load事件
1、它是基于DOM0事件綁定完成的祭刚,所以在同一個(gè)頁(yè)面中只能給它綁定一個(gè)方法(綁定多個(gè)也以最后一個(gè)綁定的為主)

2牌捷、如果想在一個(gè)頁(yè)面中使用多次,我們應(yīng)該是基于DOM2事件綁定的

function fn1(){
    //=>第一件事情
}
function fn2(){
    //=>第二件事情
}
window.addEventListener('load',fn1,false);
window.addEventListener('load',fn2,false);
...

$(function(){}) 或者 $(document).ready(function(){})
當(dāng)文檔中的DOM結(jié)構(gòu)加載完成就會(huì)被觸發(fā)執(zhí)行涡驮,而且在同一個(gè)頁(yè)面中可以使用多次

1暗甥、JQ中提供的方法,JQ是基于DOMContentLoaded這個(gè)事件完成這個(gè)操作的
2捉捅、JQ中的事件綁定都是基于DOM2事件綁定完成的
3撤防、但是DOMContentLoaded在IE68下使用attachEvent也是不支持的,JQ在IE68中使用的是readystatechange這個(gè)事件處理的

DOM2事件綁定的兼容處理

語(yǔ)法上的兼容處理
[標(biāo)準(zhǔn)]
curEle.addEventListener('type',fn,false);
[IE6~8]
curEle.attachEvent('ontype',fn);

//=>ON:給當(dāng)前元素的某個(gè)事件綁定某個(gè)方法
var on = function (curEle, type, fn) {
    if (document.addEventListener) {
        //=>標(biāo)準(zhǔn)瀏覽器
        curEle.addEventListener(type, fn, false);
        return;
    }
    //=>IE6~8
    curEle.attachEvent('on' + type, fn);
};

//=>OFF:移除當(dāng)前元素某個(gè)事件綁定的某個(gè)方法
var off = function (curEle, type, fn) {
    if (document.removeEventListener) {
        curEle.removeEventListener(type, fn, false);
        return;
    }
    //=>IE6~8
    curEle.detachEvent('on' + type, fn);
};

除了語(yǔ)法上的區(qū)別棒口,在處理的機(jī)制上有一些區(qū)別

在IE6~8中使用attachEvent做事件綁定(把方法存放在當(dāng)前元素指定事件類型的事件池中)

1寄月、順序問題:當(dāng)事件行為觸發(fā),執(zhí)行對(duì)應(yīng)事件池中存放方法的時(shí)候无牵,IE低版本瀏覽器執(zhí)行方法的順序是亂序(標(biāo)準(zhǔn)瀏覽器是按照綁定的先后順序依次執(zhí)行的)

2漾肮、重復(fù)問題:IE低版本瀏覽器在向事件池中增加方法的時(shí)候,沒有去重機(jī)制茎毁,哪怕當(dāng)前方法已經(jīng)存放過了克懊,還會(huì)重復(fù)的添加進(jìn)去(標(biāo)準(zhǔn)瀏覽器的事件池機(jī)制很完善,可以自動(dòng)去重:已經(jīng)存在過的方法不允許在添加進(jìn)來)

3七蜘、THIS問題:IE低版本瀏覽器中谭溉,當(dāng)事件行為觸發(fā),把事件池中方法執(zhí)行橡卤,此時(shí)方法中的this指向window扮念,而不是像標(biāo)準(zhǔn)瀏覽器一樣,指向當(dāng)前元素本身

究其根本:其實(shí)都是IE低版本瀏覽器對(duì)于它內(nèi)置事件池處理機(jī)制的不完善導(dǎo)致的

DOM2事件綁定兼容處理的原理:告別LOW的IE68的內(nèi)置事件池碧库,而是自己創(chuàng)建一個(gè)類似于標(biāo)準(zhǔn)瀏覽器的“自定義事件池”柜与,標(biāo)準(zhǔn)瀏覽器不需要處理兼容,只有IE68中才需要處理兼容

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谈为,一起剝皮案震驚了整個(gè)濱河市旅挤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌伞鲫,老刑警劉巖粘茄,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡柒瓣,警方通過查閱死者的電腦和手機(jī)儒搭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芙贫,“玉大人搂鲫,你說我怎么就攤上這事』瞧剑” “怎么了魂仍?”我有些...
    開封第一講書人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)拣挪。 經(jīng)常有香客問我擦酌,道長(zhǎng),這世上最難降的妖魔是什么菠劝? 我笑而不...
    開封第一講書人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任赊舶,我火速辦了婚禮,結(jié)果婚禮上赶诊,老公的妹妹穿的比我還像新娘笼平。我一直安慰自己,他們只是感情好舔痪,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開白布寓调。 她就那樣靜靜地躺著,像睡著了一般辙喂。 火紅的嫁衣襯著肌膚如雪捶牢。 梳的紋絲不亂的頭發(fā)上鸠珠,一...
    開封第一講書人閱讀 52,696評(píng)論 1 312
  • 那天巍耗,我揣著相機(jī)與錄音,去河邊找鬼渐排。 笑死炬太,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的驯耻。 我是一名探鬼主播亲族,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼可缚!你這毒婦竟也來了霎迫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤帘靡,失蹤者是張志新(化名)和其女友劉穎知给,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涩赢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年戈次,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筒扒。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡怯邪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出花墩,到底是詐尸還是另有隱情悬秉,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布冰蘑,位于F島的核電站搂捧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏懂缕。R本人自食惡果不足惜允跑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望搪柑。 院中可真熱鬧聋丝,春花似錦、人聲如沸工碾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)渊额。三九已至况木,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間旬迹,已是汗流浹背火惊。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留奔垦,地道東北人屹耐。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像椿猎,于是被迫代替她去往敵國(guó)和親惶岭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • ??JavaScript 與 HTML 之間的交互是通過事件實(shí)現(xiàn)的。 ??事件筐咧,就是文檔或?yàn)g覽器窗口中發(fā)生的一些特...
    霜天曉閱讀 3,503評(píng)論 1 11
  • 事件流分為兩種鸯旁,捕獲事件流和冒泡時(shí)間流 捕獲事件流:從根節(jié)點(diǎn)出發(fā)開始執(zhí)行,一直往子節(jié)點(diǎn)查找執(zhí)行,直到查到到根節(jié)點(diǎn)羡亩。...
    路上靈魂的自由者閱讀 397評(píng)論 0 0
  • 前言 本文主要介紹: DOM事件級(jí)別 DOM事件流 DOM事件模型 事件代理 Event對(duì)象常見的方法和屬性 一摩疑、...
    xyyojl閱讀 1,220評(píng)論 0 3
  • 事件流 JavaScript與HTML之間的交互是通過事件實(shí)現(xiàn)的。事件畏铆,就是文檔或?yàn)g覽器窗口中發(fā)生的一些特定的交互...
    DHFE閱讀 834評(píng)論 0 3
  • 22雷袋、JQ的基礎(chǔ)語(yǔ)法、核心原理和項(xiàng)目實(shí)戰(zhàn) jQ的版本和下載 jQuery版本 1.x:兼容IE6-8辞居,是目前PC端...
    萌妹撒閱讀 1,759評(píng)論 0 0