最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JS事件處理機制及事件代理(事件委托)實例詳解

 更新時間:2023年06月21日 09:27:09   作者:flying_huixia  
這篇文章主要介紹了JS事件處理機制及事件代理,結合實例形式詳細分析了JS時間處理機制與事件代理功能、用法及相關使用技巧,需要的朋友可以參考下

一、先記個小知識點。cssText

cssText 本質:設置 HTML 元素的 style 屬性值。

用法:document.getElementById("d1").style.cssText= "color:red; font-size:13px;";

cssText 返回值:在某些瀏覽器中(比如 Chrome),你給他賦什么值,它就返回什么值。在 IE 中則比較痛苦,它會格式化輸出、會把屬性大寫、會改變屬性順序、會去掉最后一個分號,比如:

cssText的使用優(yōu)勢:樣式一多,代碼就很多;而且通過JS來覆寫對象的樣式是比較典型的一種銷毀原樣式并重建的過程,這種銷毀和重建,都會增加瀏覽器的開銷。語法為:obj.style.cssText=”樣式”;這樣就可以盡量避免頁面reflow,提高頁面性能。

但是,這樣會有一個問題,會把原有的cssText清掉,比如原來的style中有’display:none;’,那么執(zhí)行完上面的JS后,display就被刪掉了。為了解決這個問題,可以采用cssText累加的方法:

Element.style.cssText += 'width:100px;height:100px;top:100px;left:100px;'

注意:上面cssText累加的方法在IE中是無效的。解決辦法是,可以在前面添加一個分號來解決這個問題:

Element.style.cssText += ';width:100px;height:100px;top:100px;left:100px;'

補充:如果前面有樣式表文件寫著 div {text-decoration:underline; },這個會被覆蓋嗎?不會!因為它不是直接作用于 HTML元素的 style 屬性。

二、JS的事件處理機制

1、事件流:指從頁面中接收事件的順序,有冒泡流和捕獲流。

2、DOM2級事件規(guī)定事件流包括三個階段:事件捕獲階段、處于目標階段、事件冒泡階段。首先發(fā)生的是事件捕獲,然后是實際的目標接收道事件,最后是冒泡階段,可以在這個階段對事件做出響應。

分析:實際的(text)元素在捕獲階段不會接收到事件,意味著在捕獲階段,事件從document到<body>再到<div>后就停止了。下一個階段是“處于目標階段”,于是事件在(text)上發(fā)生,并在事件處理中被看成是冒泡階段的一部分。最后,冒泡階段發(fā)生,事件又傳播回文檔。

3、事件處理程序

諸如click,load,mouseover都是事件的名字,而響應某個事件的函數就是事件處理程序(事件偵聽器)。事件處理程序的名字以on開頭,比如onclick.onmouseover等。

(1)HTML事件處理程序:某個元素支持的每種事件,都可以用一個相應事件處理程序同名的HTML特性來決定。

<input type="button" value="click" οnclick="alert('clicked')"/>
<input type="button" value="click" οnclick="alert(event.type)"/>

第二動態(tài)創(chuàng)建的函數中會有一個局部變量event,也就是事件對象。通過event變量,可以直接訪問事件對象。

另外,這個動態(tài)創(chuàng)建的函數擴展作用域的方式如下:使用with

在這個函數內部,可以像訪問局部變量一樣訪問document及該元素本身的成員。

function(){
   with(documnet){
       with(this){
          /元素屬性值
     }
  }
}

(2)DOM0級事件處理程序

基于DOM0的事件,對于同一個dom節(jié)點而言,只能注冊一個,后邊注冊的 同種事件 會覆蓋之前注冊的。利用這個原理我們可以解除事件,btn5.onclick=null;其中this就是綁定事件的那個元素;

這里添加的事件處理程序是在其依附的元素的作用域中運行。

DOM0級對每個事件只支持一個事件處理程序。

(3)DOM2級事件處理程序

DOM2支持同一dom元素注冊多個同種事件,事件發(fā)生的順序按照添加的順序依次觸發(fā)(IE是相反的)。DOM2事件通過addEventListener和removeEventListener管理。  DOM2級事件定義了兩個方法,用于處理指定和刪除事件處理程序的操作:addEventListener(eventName,handlers,boolean)和removeEventListener(),兩個方法都一樣接收三個參數, 要處理的事件名,第二個是 事件處理程序函數,第三個值為 布爾值。
布爾值是true,表示在捕獲階段調用事件處理程序。false時表示在事件冒泡階段調用事件處理程序,一般建議在冒泡階段使用,特殊情況才在捕獲階段; 注意:通過addEventListener() 添加的事件處理程序只能用removeEventListener() 來移除,并且移除時傳入的參數必須與添加時傳入的參數一樣;通過addEventListener()添加的匿名函數將無法移除。(js高程P351-P352)
使用DOM2級事件處理程序可以添加多個事件處理程序:

var btn2 = document.getElementById('btn2');
var handlers = function () {
   console.log(this.id);
 };
btn2.addEventListener('click',handlers,false);
btn2.addEventListener("click",function(){alert("hello")},false);
btn2.removeEventListener('click',handlers.false);

這里為按鈕添加了兩個事件處理程序,他們會按照添加他們的順序觸發(fā)。

(4)IE事件處理程序

IE用了attachEvent(),和detachEvent(),接收兩個參數,事件名稱和事件處理程序函數。由于IE8及以前只支持事件冒泡;通過attachEvent()添加的事件處理程序都會被添加到冒泡階段。所以平時為了兼容更多的瀏覽器最好將事件添加到事件冒泡階段。

 var btn3 = document.getElementById('btn3');
 var handlers2=function(){
  console.log(this===window);//true,注意attachEvent()添加的事件處理程序運行在全局作用域中;
 };
?btn3.attachEvent('onclick',handlers2);

分析:attachEvent()的第一個參數是“onclick”DOM則是“click”

重點:在使用attachEvent()方法的情況下,事件處理程序會在全局作用域中運行。因此this等于window。

attachEvent()也可以為同一元素添加兩個不同的事件處理程序。只是執(zhí)行事件時以相反的順序被觸發(fā)。

(5)跨瀏覽器事件處理程序

為了以跨瀏覽器的方式處理事件,有兩個方法,addHandler(),它的職責是視情況分別使用DOM0和DOM2或者IE方法來添加或刪除事件。這個方法屬于一個名叫EventUtil的對象,可以處理瀏覽器差異。這個方法接收三個參數。要操作的元素、事件名稱、和事件處理程序函數。對應的方法是removeHandler()函數,它的職責是移除事件處理程序。默認采用DOM0級方法。

4 事件對象

觸發(fā)DOM上的某個事件時,會產生一個事件對象event,這個對象中包含了所有與事件有關的信息,比如導致事件的元素target,事件的類型,及其他特定的相關信息。例如鼠標操作導致的事件對象中會包含鼠標的位置,單雙擊等,而鍵盤操作導致的事件對象會包含按下的鍵等信息;

 事件被觸發(fā)時,會默認給事件處理程序傳入一個參數e , 表示事件對象;通過e,我們可以獲得其中包含的與事件有關的信息;  只有在事件處理程序執(zhí)行期間,event對象才會存在,一旦事件處理程序執(zhí)行完畢,event對象就會被銷毀;

(1)DOM中的事件對象

兼容DOM的瀏覽器會自動將一個事件對象event傳遞給事件處理程序。

在通過HTML特性指定事件處理函數時,變量event中保存著event對象。event對象包含與創(chuàng)建它的特定事件的有關的屬性和方法。觸發(fā)的事件類型不一樣,可用的屬性和方法也不一樣。

currentTarget只讀事件處理程序當前正在處理事件的那個元素
datail只讀與事件相關的細節(jié)
eventPhase只讀調用事件處理程序的階段1 捕獲階段 2  處于目標 3 冒泡階段
target只讀事件的目標
type只讀被觸發(fā)的事件的類型

在事件處理程序內部,對象this始終等于currentTarget的值,target包含事件的實際目標。

ps:關于事件對象中的this,target,currentTarget,看個例子:(注:event.target不支持IE瀏覽器,應該用event.srcElement;還有 IE中通過attachment添加的事件是運行在全局作用域中的,this===window。

preventDefault() 阻止事件的默認行為,只有cancelabel屬性的值設為true時,才可以使用preventDefalut.
event.stopPropagation()可以阻止事件的傳播.,取消進一步的事件冒泡或者捕獲

(2)IE中的事件對象

要訪問IE的event對象有幾種不同的方式,取決于指定事件處理程序的方法。

比如使用DOM0級方法添加事件處理程序時,event對象作為window對象的一個屬性存在,因此可以通過window.event來訪問event對象。

var btn=document.getElementById("myBtn");
btn.οnclick=function(){
   var event=window.event;
   alert(event.type);
}

輸出結果是click.
如果是使用attachEvent()來添加事件處理程序,那么會有一個對象作為參數傳入事件處理程序函數中。

var btn=document.getElementById("myBtn");
btn.attachEvent("onclick",function(event){
   alert(event.type);
});

輸出結果是click.

IE中event對象同樣包含與創(chuàng)建它的事件相關的方法和屬性。其中很多屬性和方法都有對應的或者相關的DOM屬性和方法。這些屬性和方法會因為事類型的不同而不同。

srcElement只讀事件的目標(與DOM中target屬性相同)
type只讀被觸發(fā)的事件的類型
cancelBubble讀/寫默認值為false,設置為true可以取消事件冒泡(與DOM中stopPropagation()一樣)
returnValue讀/寫默認為true,設置為false,就可以阻止默認行為。(與DOM中的preventDefault()一樣)
將returnValue設置為false,就可以阻止默認行為。
cancelBubble屬性值為true,可以取消事件冒泡。

(3)跨瀏覽器的事件對象

雖然DOM和IE中對象不同,但基于二者之間的相似性依舊可以拿出跨瀏覽器的方案來。

IE中的event中的全部信息和方法都是類似的只是實現方式不同,可以用前面提到過的EventUtil對象來求同存異。

var EventUtil(){
     addHandler:function(element,type,handler){
//省略代碼
},
getEvent:function(event){
 return event?event:window.event;
   },
getTarget:function(event){
   return event.target||event.srcElement;
   },
preventDefault:function(event){
      if(event.preventDefault){
      event.preventDefault();
  }else{
      event.returnValue=false;
      }
  ?},
   removeHandler:function(element,type,handler){
    //省略代碼
},
stopPropagation:function(event){
?if(event.stopPropagation){
      event.preventDefault();
  }else{
event.cancelBubble=true; }
}
};

以上代碼為EventUtil 添加了4個方法;getEvent(),返回event對象的引用。其它方法類似。

5 事件委托

因為冒泡機制,比如既然點擊子元素,也會觸發(fā)父元素的點擊事件,那我們完全可以將子元素的事件要做的事寫到父元素的事件里,也就是將子元素的事件處理程序寫到父元素的事件處理程序中,這就是事件委托;利用事件委托,只指定一個事件處理程序,就可以管理某一個類型的所有事件;

通俗來說:事件委托是利用事件的冒泡原理來實現的,何為事件冒泡呢?就是事件從最深的節(jié)點開始,然后逐步向上傳播事件,舉個例子:頁面上有這么一個節(jié)點樹,div>ul>li>a;比如給最里面的a加一個click點擊事件,那么這個事件就會一層一層的往外執(zhí)行,執(zhí)行順序a>li>ul>div,有這樣一個機制,那么我們給最外面的div加點擊事件,那么里面的ul,li,a做點擊事件的時候,都會冒泡到最外層的div上,所以都會觸發(fā),這就是事件委托,委托它們父級代為執(zhí)行事件。

示例1:

<ul>
    <li>111</li>
    <li>222</li>
    <li>333</li>
    <li>444</li>
</ul>

實現點擊li出現123.

傳統(tǒng)方法:

window.onload = function(){
    var oUl = document.getElementById("ul1");
    var aLi = oUl.getElementsByTagName('li');
    for(var i=0;i<aLi.length;i++){
        aLi[i].onclick = function(){
            alert(123);
        }
    }
}

使用事件委托:

window.onload = function(){
    var oUl = document.getElementById("ul1");
   oUl.onclick = function(){
        alert(123);
    }
}

這里用父級ul做事件處理,當li被點擊時,由于冒泡原理,事件就會冒泡到ul上,因為ul上有點擊事件,所以事件就會觸發(fā),當然,這里當點擊ul的時候,也是會觸發(fā)的,那么問題就來了,如果我想讓事件代理的效果跟直接給節(jié)點的事件效果一樣怎么辦,比如說只有點擊li才會觸發(fā)???

示例2:

Event對象提供了一個屬性叫target,可以返回事件的目標節(jié)點,我們成為事件源,也就是說,target就可以表示為當前的事件操作的dom,但是不是真正操作dom,當然,這個是有兼容性的,標準瀏覽器用ev.target,IE瀏覽器用event.srcElement。

window.onload = function(){
  var oUl = document.getElementById("ul1");
  oUl.onclick = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    if(target.nodeName.toLowerCase() == 'li'){
         alert(123);
         alert(target.innerHTML);
    }
  }
}

這樣,只有點擊li才會觸發(fā)事件。

示例3

對比下列兩段代碼實現:

window.onload = function(){
            var oBtn = document.getElementById("btn");
            var oUl = document.getElementById("ul1");
            var aLi = oUl.getElementsByTagName('li');
            var num = 4;
            //鼠標移入變紅,移出變白
            for(var i=0; i<aLi.length;i++){
                aLi[i].onmouseover = function(){
                    this.style.background = 'red';
                };
                aLi[i].onmouseout = function(){
                    this.style.background = '#fff';
                }
            }
            //添加新節(jié)點
            oBtn.onclick = function(){
                num++;
                var oLi = document.createElement('li');
                oLi.innerHTML = 111*num;
                oUl.appendChild(oLi);
            };
        }

注意:這里添加的新節(jié)點并不會有事件處理程序。

window.onload = function(){
            var oBtn = document.getElementById("btn");
            var oUl = document.getElementById("ul1");
            var aLi = oUl.getElementsByTagName('li');
            var num = 4;
            //事件委托,添加的子元素也有事件
            oUl.onmouseover = function(ev){
                var ev = ev || window.event;
                var target = ev.target || ev.srcElement;
                if(target.nodeName.toLowerCase() == 'li'){
                    target.style.background = "red";
                }
            };
            oUl.onmouseout = function(ev){
                var ev = ev || window.event;
                var target = ev.target || ev.srcElement;
                if(target.nodeName.toLowerCase() == 'li'){
                    target.style.background = "#fff";
                }
            };
            //添加新節(jié)點
            oBtn.onclick = function(){
                num++;
                var oLi = document.createElement('li');
                oLi.innerHTML = 111*num;
                oUl.appendChild(oLi);
            };
        }

用事件委托的方式,新添加的子元素是帶有事件效果的,我們可以發(fā)現,當用事件委托的時候,根本就不需要去遍歷元素的子節(jié)點,只需要給父級元素添加事件就好了,其他的都是在js里面的執(zhí)行,這樣可以大大的減少dom操作,這才是事件委托的精髓所在。

示例4: 點擊某一個 Li 標簽時,將 Li 的背景色顯示在 P 標簽內,并將 P 標簽中的文字顏色設置成 Li 的背景色

傳統(tǒng)實現:

 var list = document.querySelectorAll("li");
    for (var i = 0, len = list.length; i < len; i++) {
        list[i].onclick = function(e) {
            var t = e.target;
            var c = t.style.backgroundColor;
            var p = document.getElementsByClassName("color-picker")[0];
            p.innerHTML = c;
            p.style.color = c;
        }
    }

運用事件委托:

   var ulist=document.getElementsByClassName("palette")[0];
    ulist.οnclick=function(ev){
        var ev = ev || window.event;
        var target = ev.target || ev.srcElement;
        if (target.nodeName.toLowerCase() === 'li') {
                var c = target.style.backgroundColor;
                var p = document.getElementsByClassName("color-picker")[0];
                p.innerHTML = c;
                 p.style.color = c;
        }
    }

注意:ul只有一個,要用索引,[0],如果不寫,無法實現。
總結一下js委托相關的:

  • 因為把事件綁定到了父節(jié)點上,因此省了綁定事件。就算后面新增的子節(jié)點也有了相關事件,刪除部分子節(jié)點不用去銷毀對應節(jié)點上綁定的事件
  • 父節(jié)點是通過event.target來找對應的子節(jié)點的。(事件處理程序中的this值始終等于currentTarget的值,指向的是綁定到的那個元素)

相關文章

  • layui點擊按鈕頁面會自動刷新的解決方案

    layui點擊按鈕頁面會自動刷新的解決方案

    今天小編就為大家分享一篇layui點擊按鈕頁面會自動刷新的解決方案,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-10-10
  • 小程序Scroll-view上拉滾動刷新數據

    小程序Scroll-view上拉滾動刷新數據

    這篇文章主要為大家詳細介紹了小程序Scroll-view上拉滾動刷新數據,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-06-06
  • Bootstrap彈出框(modal)垂直居中的問題及解決方案詳解

    Bootstrap彈出框(modal)垂直居中的問題及解決方案詳解

    這篇文章主要介紹了Bootstrap彈出框(modal)垂直居中的問題及解決方案詳解的相關資料,非常不錯具有參考借鑒價值,需要的朋友可以參考下
    2016-06-06
  • JS獲取鼠標坐標位置實例分析

    JS獲取鼠標坐標位置實例分析

    這篇文章主要介紹了JS獲取鼠標坐標位置的方法,結合實例形式分析了JavaScript常見的獲取鼠標頁面、屏幕等坐標位置的技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2016-01-01
  • director.js實現前端路由使用實例

    director.js實現前端路由使用實例

    這篇文章主要介紹了director.js實現前端路由使用實例,director.js是最純粹的路由注冊/解析器,它在不刷新頁面的情況下,利用“#”符號組織不同的URL路徑,需要的朋友可以參考下
    2015-02-02
  • 原生JS中應該禁止出現的寫法

    原生JS中應該禁止出現的寫法

    這篇文章主要介紹了原生JS中應該禁止出現的寫法,以提高代碼效率和安全性,對效率和安全感興趣的同學,可以參考下
    2021-05-05
  • javascript獲取網頁各種高寬及位置的方法總結

    javascript獲取網頁各種高寬及位置的方法總結

    下面小編就為大家?guī)硪黄猨avascript獲取網頁各種高寬及位置的方法總結。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-07-07
  • JavaScript調用后臺的三種方法實例

    JavaScript調用后臺的三種方法實例

    這篇文章介紹了JavaScript調用后臺的三種方法實例,有需要的朋友可以參考一下
    2013-10-10
  • JavaScript?中?import()?的動態(tài)加載原理解析

    JavaScript?中?import()?的動態(tài)加載原理解析

    import()的動態(tài)加載原理基于JavaScript的模塊系統(tǒng)和異步編程模型,通過返回Promise實現模塊的按需、異步加載,本文給大家介紹JavaScript中import()的動態(tài)加載原理,感興趣的朋友一起看看吧
    2025-10-10
  • 原生js實現2048小游戲

    原生js實現2048小游戲

    這篇文章主要為大家詳細介紹了原生js實現2048小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-03-03

最新評論

彰化市| 池州市| 沛县| 衡阳市| 新河县| 延川县| 长岛县| 健康| 龙口市| 宁津县| 宁乡县| 老河口市| 昌吉市| 宜宾市| 梁河县| 常德市| 田林县| 贵定县| 磐安县| 湄潭县| 贞丰县| 通山县| 孟连| 大邑县| 万盛区| 昌邑市| 墨竹工卡县| 白河县| 德昌县| 米脂县| 台湾省| 无为县| 昭通市| 日喀则市| 南靖县| 武宁县| 吉安市| 涞水县| 江华| 尼勒克县| 如皋市|