事件處理

1.事件代理

  • 事件代理:為子元素添加監聽器轉變為為父容器添加監聽器,然后通過event.target判斷具體操作的元素
  • 事件的傳遞是和文檔結構有關的

1.DOM0級和DOM2級在事件監聽使用方式上有什么區別?

  • DOM0級事件處理程序

    • 使用DOM0級方法指定的事件處理程序被認為是元素的方法,因此,事件處理程序是在元素的作用域中運行
    var btn = document.getElementById('btn');
    btn.onclick = function (){
      console.log(this.id);  // btn
    }
    
    • 使用DOM0級方法只能為元素的一個事件指定一個處理程序,后面指定的會覆蓋前面指定的(因為事件處理程序被認為是元素的方法,同一事件則方法名相同)
    // 后一個事件處理程序會覆蓋前一個事件處理程序
    var btn = document.getElementById('btn');
    btn.onclick = function (){
      console.log(this.id);  
    }
    btn.onclick = function (){
      console.log("hello");  
    }
    
    • 使用DOM0級方法刪除事件處理程序
    var btn = document.getElementById('btn');
    btn.onclick = function (){
      console.log(this.id);  
    }
    btn.onclick = null;
    
    • 使用DOM0級方法指定的事件處理程序兼容IE較低版本
  • DOM2級事件處理程序

    • 使用DOM2級方法指定的事件處理程序
    var btn = document.getElementById('btn');
    btn.addEventListener("click", function(){
      console.log("test");
    });
    
    function handler(){
      console.log("test");
    }
    var btn = document.getElementById('btn');
    btn.addEventListener("click", handler);
    
    • 使用DOM2級方法可以為元素針對多個事件指定多個處理程序,這些事件處理程序會按照添加順序依次執行
    var btn = document.getElementById('btn');
    function handler(){
      console.log("test");
    }
    btn.addEventListener("click", function(){
      console.log("test");
    });
    btn.addEventListener("click", handler);
    
    • 使用DOM2級方法可以為元素刪除事件處理程序,但是指定的匿名事件處理函數無法刪除
    btn.removeEventListener("click", handler);
    
    • 使用DOM2級事件處理程序可以指定在哪一階段調用事件處理程序(捕獲階段or冒泡階段)
    btn.addEventListener("click", handler, false); // 在冒泡階段調用事件處理程序
    btn.addEventListener("click", handler, true); // 在捕獲階段調用事件處理程序
    
    • 使用addEventListener為元素添加的事件處理程序也是在其依附的元素的作用域中運行
    var btn = document.getElementById('btn');
    function handler(){
        console.log(this.id);
    }
    btn.addEventListener("click", handler);  // 觸發時輸出 btn
    

2.attachEvent與addEventListener的區別?

  • 在低版本IE瀏覽器中,只支持事件冒泡,因此不支持addEventListener和removeEventListener方法,但是實現了類似的兩個方法:attachEvent和detachEvent
  • addEventListener:
    • 可以指定2或3個參數
    • 可以指定在哪一階段調用事件處理程序(捕獲階段or冒泡階段),默認是冒泡階段
    • addEventListener第一個參數是事件類型(比如click,load)
    • 為元素添加的事件處理程序是在其依附的元素的作用域中運行
    • addEventListener針對一個事件添加的多個事件處理程序會按照添加順序執行
  • attachEvent:
    • 只能指定2個參數
    • 添加的事件處理程序都會在冒泡階段被執行,無法指定在哪一階段調用事件處理程序
    • attachEvent第一個參數是事件處理函數名稱(比如onclick,onload)
    • 為元素添加的事件處理程序是在全局作用域中運行
    • 事件處理函數名稱針對一個事件添加的多個事件處理程序會無規律執行

3.解釋IE事件冒泡和DOM2事件傳播機制?

  • IE的事件冒泡:事件開始時由最具體的元素接收,然后逐級向上傳播到較為不具體的元素
  • Netscape的事件捕獲:不太具體的節點更早接收事件,而最具體的元素最后接收事件,和事件冒泡相反
  • DOM事件流:DOM2級事件規定事件流包括三個階段,事件捕獲階段,處于目標階段,事件冒泡階段,首先發生的是事件捕獲,為截取事件提供機會,然后是實際目標接收事件,最后是冒泡階段

4.如何阻止事件冒泡? 如何阻止默認事件?

  • 阻止事件冒泡:event.stopPropagation();
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    <h1>hello!</h1>
</div>
<script>
    var html = document.documentElement;
    var body = document.body;
    var div = document.querySelector("div");
    var h1 = document.querySelector("h1");
    window.addEventListener("click",function(){
        console.log(1);
    },true);
    window.addEventListener("click",function(){
        console.log(1);
    });
    document.addEventListener("click",function(){
        console.log(2);
    },true);
    document.addEventListener("click",function(){
        console.log(2);
    });
    html.addEventListener("click",function(){
        console.log(3);
    },true);
    html.addEventListener("click",function(){
        console.log(3);
    });
    body.addEventListener("click",function(){
        console.log(4);
    },true);
    body.addEventListener("click",function(){
        console.log(4);
    });
    div.addEventListener("click",function(){
        console.log(5);
        //如果沒有阻止捕獲/冒泡,點擊hello! 會輸出1 2 3 4 5 6 6 5 4 3 2 1
        //如果阻止捕獲/冒泡,點擊hello! 會輸出1 2 3 4 5
        event.stopPropagation();
    },true);
    div.addEventListener("click",function(){
        console.log(5);
    });
    h1.addEventListener("click",function(){
        console.log(6);
    },true);
    h1.addEventListener("click",function(){
        console.log(6);
    });
</script>
</body>

</html>
  • 阻止默認事件:event.preventDefault();
//阻止點擊a標簽后導致的頁面跳轉
<a href="www.baidu.com" id="link">baidu</a>
<script>
function prevent(event){
    event.preventDefault();
}
var link = document.getElementById("link");
link.addEventListener("click", prevent);
</script>

5.有如下代碼,要求當點擊每一個元素li時控制臺展示該元素的文本內容。

  • 事件委托/事件代理:對于"事件處理程序過多"問題的解決方案就是事件委托/事件代理.事件委托利用了事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件.使用事件委托結束解決以下問題,只需要在DOM樹中盡量高的層次上添加一個事件處理程序.
<ul class="ct">
    <li>aaaa</li>
    <li>bbbb</li>
    <li>cccc</li>
</ul>
<script>
function outputInnerText(event){
    var target = event.target;
    console.log(target.innerHTML);
}
var ul = document.querySelector(".ct");
ul.addEventListener("click", outputInnerText);
</script>

6.補全代碼,要求:

  • 當點擊按鈕開頭添加時在<li>這里是</li>元素前添加一個新元素,內容為用戶輸入的非空字符串;當點擊結尾添加時在最后一個 li 元素后添加用戶輸入的非空字符串.
  • 當點擊每一個元素li時控制臺展示該元素的文本內容。
<div>
    <ul class="ct">
        <li>aaaa</li>
        <li>bbbb</li>
        <li>cccc</li>
    </ul>
    <input class="ipt-add-content" placeholder="添加內容"/>
    <button id="btn-add-start">開頭添加</button>
    <button id="btn-add-end">結尾添加</button>
</div>
<script>
    var ul = document.querySelector(".ct");
    var btn_add_start = document.querySelector("#btn-add-start");
    var btn_add_end = document.querySelector("#btn-add-end");
    var content = document.querySelector(".ipt-add-content");
    btn_add_start.onclick = function (event) {
        if(content.value.length < 1 ){
            alert('請輸入項目名稱');
        }else{
            var newNode = document.createElement("li");
            newNode.innerHTML = content.value;
            ul.insertBefore(newNode, ul.firstElementChild);
            content.value = "";
        }
    }
    btn_add_end.onclick = function (event) {
        if(content.value.length < 1 ){
            alert('請輸入項目名稱');
        }else{
            var newNode = document.createElement("li");
            newNode.innerHTML = content.value;
            ul.appendChild(newNode);
            content.value = "";
        }
    }
    function outputInnerText(event){
        var target = event.target;
        console.log(target.innerHTML);
    }
    ul.addEventListener("click", outputInnerText);
</script>

7.補全代碼,要求:當鼠標放置在li元素上,會在img-preview里展示當前li元素的data-img對應的圖片。

<ul class="ct">
    <li data-img="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1487859573373&di=7467cab77ceaa0739cb8a0acd5857623&imgtype=0&src=http%3A%2F%2Fwww.kele8.com%2Fuploadfile%2F2014%2F0326%2F20140326034001805.jpg">鼠標放置查看圖片1</li>
    <li data-img="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1487859916531&di=cbdd990e7d9dcbcb409168363182137a&imgtype=0&src=http%3A%2F%2Fh7.86.cc%2Fwalls%2F20150906%2F1024x768_43422cf79b8229f.jpg">鼠標放置查看圖片2</li>
    <li data-img="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1487859633187&di=b78c30783aaa1c04ef82ae6f398900fd&imgtype=0&src=http%3A%2F%2Fimg1.gamedog.cn%2F2014%2F04%2F22%2F43-1404221025080.jpg">鼠標放置查看圖片3</li>
</ul>
<div class="img-preview"></div>
<script>
    //使用事件代理/事件委托
    var ul = document.querySelector(".ct");
    var imgPreview = document.querySelector(".img-preview");
    function agentMouseOver(event){
        var target = event.target;
        var imageName = target.getAttribute("data-img");
        var image = document.createElement('img');
        image.setAttribute("src", imageName);
        if(imgPreview.firstElementChild != null){
            imgPreview.replaceChild(image,imgPreview.firstElementChild );
        }else{
            imgPreview.appendChild(image);
            imgPreview.firstElementChild.addEventListener("click", prevent);
        }

    }
    ul.addEventListener("mouseover", agentMouseOver);
    function closeImage(event){
        if(imgPreview.firstElementChild != null){
            imgPreview.removeEventListener("click", prevent);
            imgPreview.removeChild(imgPreview.firstElementChild);
        }
    }
    function prevent(event){
        event.stopPropagation();
    }

    document.addEventListener("click", closeImage);
    imgPreview.addEventListener("click", prevent);
</script>

實現效果

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,013評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,346評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,421評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,146評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,534評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,767評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,318評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,074評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,258評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,486評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,916評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,156評論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,993評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,234評論 2 375

推薦閱讀更多精彩內容