事件處理模型之冒泡與捕獲,綁定與解除

事件處理模型

以下就是事件處理模型例子的代碼

 <style>
    .red{
        width: 200px;
        height: 200px;
        background-color: red;
    }
    .green{
        width: 150px;
        height: 150px;
        background-color: green;
    }
    .yellow{
        width: 100px;
        height: 100px;
        background-color: yellow;
    }
    </style>
  <div class = "red">
       <div class = "green">
           <div class = "yellow">              
           </div>
       </div>
   </div>

  <script>
    var red = document.getElementsByClassName('red')[0];
    var green = document.getElementsByClassName('green')[0];
    var yellow = document.getElementsByClassName('yellow')[0];
    red.addEventListener('click',function(){
        console.log("red");
    },false);
    green.addEventListener('click',function(){
        console.log("green");
    },false);
    yellow.addEventListener('click',function(){
        console.log("yellow");
    },false);
   </script> 
冒泡

html結構上(非視覺上)嵌套關係的元素,會存在事件冒泡的功能,即同一事件,自子元素冒泡向父元素。(結構上自底向上

下層的DOM節點定義的事件處理函數,到了上層的節點如果還有和下層相同事件類型的事件處理函數,那麼上層的事件處理函數也會執行。
在這裏插入圖片描述在這裏插入圖片描述

捕獲

html結構上(非視覺上)嵌套關係的元素,會存在事件捕獲的功能,即同一事件,自父元素捕獲至子元素(事件源元素)。(結構上自頂向下
elem.addEventListener(‘type’,fn,true);第三個參數爲true就是開啓了事件捕獲
在這裏插入圖片描述在這裏插入圖片描述
IE沒有捕獲事件
事件捕獲有chrome瀏覽器實現了,最新版本的火狐,opera也有,老版本沒有

觸發順序,先捕獲,後冒泡
  • 同一個對象的同一個事件類型上面綁定了一個理函數只能遵循一種處理模型,就是說一個元素綁定了一個事件處理函數,那麼這個事件處理函數要麼就是事件冒泡的處理模型,要麼就是事件捕獲的處理模型。
  • 同一個對象的同一個事件類型上面綁定了兩個事件處理函數,一個是事件冒泡,一個是事件捕獲,觸發順序就是先捕獲再冒泡。
    在這裏插入圖片描述

參數false事件爲冒泡行爲
參數爲true事件爲捕獲行爲
在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

focus,blur,change,submit,reset,select等事件不冒泡

取消冒泡事件

event.stopPropagation() W3C標準(IE9以下不支持)
event.cancelBubble = true IE獨有
封裝一個函數取消事件冒泡 (兼容版)

function stopBubble(event) {
   if (event.stopPropagation) {
       event.stopPropagation();
   } else {
       event.cancelBubble = true;
   }
}

阻止默認事件

默認事件
表單提交,a標籤跳轉或者刷新頁面,點擊右鍵彈出菜單等

  1. return false
    以句柄(elem.onXXX = fn)的方式綁定的事件才生效
  2. event.prevetDefault()
    W3C標註,IE9以下不兼容
  3. event.returnValue = false
    兼容IE

封裝阻止默認事件的函數(兼容版)

function cancelHandler(event) {
    if(event.prevetDefault){
        event.prevetDefault();
    }else{
        event.returnValue = false;//包括了兼容IE的,也包括了以句柄形式的return false;
    }
}

阻止a標籤默認跳轉或者刷新頁面,阻止點擊右鍵默認彈出菜單

  • 阻止a標籤默認跳轉或者刷新頁面
//第一種方式
 <a href="javascript:void()">demo</a>
 //void()裏面相當於返回什麼

//第一種方式
var a = document.getElementsByTagName('a')[0];
a.onclick = function(){
    return false;
}
  • 阻止點擊右鍵默認彈出菜單
//第一種方式
	 document.oncontextmenu = function(){
        console.log('a');
        return false;
    }
    
//第二種方式
	 document.oncontextmenu = function (e) {
	     console.log('a');
	     cancelHandler(e);
	 }
    function cancelHandler(event) {
        if(event.prevetDefault){
            event.prevetDefault();
        }else{
            event.returnValue = false;
        }
    }

JS-阻斷事件傳播:
1:stopPropagation(原生js上的):
2:preventDefault
3:stopImmediatePropagation(jquery上的)

stopImmediatePropagation做了兩件事情:

  • 第一件事:阻止 綁定在事件觸發元素的 其他同類事件的callback的運行。

  • 第二件事,阻止事件傳播到父元素,這跟stopPropagation的作用是一樣的

  • stopImmediatePropagation();這個函數用於阻斷同一element的事件傳播。

    例如一個element上定義了多個listener,如果其中一個調用這個方法後面的listener則都不會執行。

事件對象

1,事件對象:在觸發DOM上的某個事件的時候,會產生一個事件對象event,而在這個對象當中會包含着所有與事件有關的信息。(事件對象的屬性詳解:(https://blog.csdn.net/weixin_43623871/article/details/88894094))

2,事件對象的兼容寫法:
var event =e || window.event (用於IE);

3,事件對象其中有兩個信息,我們最爲常用,分別是type和target:

  1. type:事件的類型,如onlick中的click;
  2. srcElement/target:事件源,就是發生事件的元素(dom元素);

事件源對象
event.target(火狐只有這個)
event.srcElement(IE只有這個)
chrome這兩個都有。

<div class = "red"></div>
-----------------------------
var red = document.getElementsByClassName('red')[0];
red.onclick = function(e){
	  var event = e || window.event;
	  var target = event.target || event.srcElement;
	  console.log(event);
	  console.log(target);//求事件源對象
}

在這裏插入圖片描述

事件對象和事件源對象的兼容性寫法

function(e){
	 var event = e || window.event;
	 var target = event.target || event.srcElement;
}

事件委託

要求:點擊每一個li ,打印出對應li裏面的內容

<ul>
	<li>1</li>
	<li>2</li>
	<li>3</li>
	<li>4</li>
	<li>5</li>
	<li>6</li>
	<li>7</li>
	<li>8</li>
	<li>9</li>
	<li>10</li>
</ul>

1,土辦法: 給每一個li綁定點擊事件:

var li = document.getElementsByTagName('li');
    var len = li.length;
    for(var i = 0; i < len; i++) {
        li[i].onclick = function (){
            console.log(this.innerText);
        }
    }

2,事件委託辦法:給父元素ul一個人綁定點擊事件,利用事件冒泡和事件源對象處理 ,
因爲每點擊一個li,該li就會成爲事件源對象,因爲li始終在ul裏面。

 var ul = document.getElementsByTagName('ul')[0];
  ul.onclick = function (e) {
    var event = e || window.event;
	var target = event.target || event.srcElement;
      console.log(target.innerHTML);
  }

利用事件冒泡和事件源對象進行處理

性能:不需要循環所有的元素一個個綁定事件

靈活:當有新的子元素添加將進來時不需要重新綁定事件(當有新的li的時候,土方法就要重新給新的li綁定點擊事件,但是利用事件委託就可以不用管,因爲你再加多少,它總是在ul裏面,點擊的時候它就會是target)

事件綁定

處理函數的三種方式

ele.onXXX = function(event) {}

  • 兼容性很好,但是一個元素的同一個事件只能綁定一個處理程序

  • 基本等同於寫在HTML行間上

<div style = "width: 200px;height: 100px;background-color: rgb(90, 80, 80); position:absolute;left: 0;top:0;" onclick = "console.log('a');"></div>

var div = document.getElementsByTagName('div')[0];
//1,句柄的方式就是用onXXX的綁定方式
// div.onclick = fucntion () {
//     console.log('a');
// }
//但一個元素的同一個事件上只能綁定一個處理程序

obj.addEventListener (type, fn, false);

IE9以下不兼容性,可以爲一個事件綁定多個處理程序(W3C標準綁定形式)

div.addEventListener('事件類型',處理函數(也可以放的是函數引用test),false)
一個元素的同一個事件上可以綁定多個處理函數

div.addEventListener('click',function(){
    console.log('a');
},false);
div.addEventListener('click',function(){
    console.log('b');
},false);
//a
//a        打印兩個是因爲雖然它們是兩個一模一樣的函數,但是它們還是不同的函數

div.addEventListener('click',test,false);
div.addEventListener('click',test,false);
function test(){
    console.log('a');
}
//a         因爲test是指向同一個地址函數的引用

obj.attachEvent (‘on’ + type, fn);

IE獨有,一個事件同樣可以綁定多個處理程序

事件處理程序的內部this指向

ele.onXXX = function(event) {}
程序this指向dom元素本身
obj.addEventListener (type, fn, false);
程序this指向dom元素本身

第三個參數可選,爲布爾值,指定事件是否在捕獲或者冒泡階段執行
obj.attachEvent (‘on’ + type, fn);
程序this指向window

讓attachEvent的this指向dom元素:

div.attachEvent('onclick',function() {
    handler.call(div);
});
function handler() {
//事件處理程序
}

給一個dom對象添加該事件類型的處理函數,封裝兼容性的
addEvent(elem, type, handler)

function addEvent(elem, type, handler) {
    if(elem.addEventListener) {
        elem.addEventListener(type, handler, false);
    }else if(elem.attachEvent){
        elem.attachEvent('on' + type, function () {
            handler.call(elem);
        })
    }else{
        elem['on' + type] = handler;
    }
}

解除事件綁定
ele.onclick = false/null

div.onclick = fucntion () {
    console.log('a');
}
div.onclick = null;
// 只能執行一次的事件
div.onclick = fucntion () {
    console.log('a');
    this.onclick = null;
}
ele.removeEventListener(type, fn, false);
div.addEventListener('click',function(){
    console.log('a');
},false);
div.removeEventListener('click', , false);//不好使,綁定了匿名函數,就無法解除
div.addEventListener('click',test,false);
function tset() {};
div.removeEventListener('click', test, false);

ele.detachEvent(‘on’ + type, fn);
若綁定匿名函數,則無法解除

實現一個拖拽的小功能

<div style="width: 100px;height: 100px;background-color:red;position: absolute;left: 0;top: 0"></div>
// JavaScript Document
function drag(elem){}
    var div = document.getElementsByTagName('div')[0];
    var disX,
       disY;
    div.onmousedown  = function (e) {
        disX = e.pageX - parseInt(div.style.left);//確定移動的中心點
        disY = e.pageY - parseInt(div.style.top);

        document.onmousemove = function(e) {
            var event = e || window.event;
            div.style.left = e.pageX - disX + "px";
            div.style.top = e.pageY -  disY +"px";
        }
        document.onmouseup = function (){
            div.onmousemove = null;
        }
    }

elem.setCapture(); elem.releaseCapture();
只有IE能用,它會把頁面所有的事件捕獲到自己身上,那麼就可以解決拖拽的時候,鼠標快於系統幀頻的速度

事件分類

鼠標事件

  • click

  • mousemove

  • mousedown mouseup

  • contextmenu(右鍵菜單欄)

  • mouseover mouseout

  • mouseenter mouseleave(迎合h5的新特性)
    一次click = mousedown + mouseup


document.onclick = function() {
        console.log('onclick');
    }
    document.onmousedown = function() {
        console.log('mousedown');
    }
    document.onmouseup = function() {
        console.log('mouseup');
    }

移動端onmousemove,onmousedown,onmouseup用不了
要用 touchmove ,touchstart ,touchend

使用event.button來區分鼠標事件的觸發鍵

event.x 鼠標橫軸
event.y 鼠標縱軸
event.keycode 鍵盤值
events.button==0 默認。沒有按任何按鈕。
events.button==1 鼠標左鍵
events.button==2 鼠標右鍵
events.button==3 鼠標左右鍵同時按下
events.button==4 鼠標中鍵
events.button==5 鼠標左鍵和中鍵同時按下
events.button==6 鼠標右鍵和中鍵同時按下
events.button==7 所有三個鍵都按下

click事件只能監聽左鍵,只能通過mousedown和mouseup才能區分鼠標左右鍵

document.onmousedown = function(e) {
    if(e.button == 2){
        console.log('right');
    }else if(e.button == 0){
        console.log('left');
    }
}

案例:實現一個a標籤的小方塊拖拽(拖拽不等於點擊)
用時間差來確定它是點擊還是拖拽,點擊的時間差是非常短的。

var firstTime = 0;
var lastTime = 0;
var key = false;
document.onmousedown = function () {
    firstTime = new Date().getTime();
}
document.onmouseup = function () {
    lastTime = new Date().getTime();
    if(lastTime - firstTime < 300){
        key = true;
    }
}
document.onclick = function () {
    if(key){
        console.log('click');
        key = false;
    }
}

鍵盤事件

  • keydown

  • keyup

  • keypress

  • keydown > keypress > keyup

    keydown 和keypress很相似,但是也有區別
    keydown 可以敲響任意按鍵
    keypress只可以敲響字符類鍵盤按鍵,然後返回ASCII碼,可以轉換成相應字符

//轉換成相應字符

document.onkeypress = function (e) {
    console.log(String.fromCharCode(e.CharCode));
}

//一次keypress 不等於keydown + keyup, 它們是這樣的關係:keydown > keypress > keyup

 document.onkeypress = function() {
       console.log('onkeypress');
   }
   document.onkeydown = function() {
       console.log('onkeydown');
   }
   document.onkeyup = function() {
       console.log('keyup');
   }

文本操作事件

  • input

  • focus

  • blur

  • change
    input事件監聽input輸入欄的值

var input = document.getElementsByTagName('input')[0];  
input.oninput = function(e){
    console.log(this.value);
}

change事件其實是比較聚焦前和失焦時候的兩個狀態的不同

var input = document.getElementsByTagName('input')[0];  
input.onchange = function(e){
    console.log(this.value);
}

實現輸入欄的聚焦輸入信息,失焦依舊有提示信息

<input type = "text" value="請輸入用戶名" onfocus="if(this.value == '請輸入用戶名'){this.value = ''}" onblur="if(this.value == ''){this.value = '請輸入用戶名'}">

窗體操作類(window上的事件)

  • scroll

  • load(window.onload()是要等到DomTree和CssTree生成後渲染成RenderTree後,纔開始調用js)

ie6沒有position : fixed定位
實現兼容

JavaScript 事件參考手冊
在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述 在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章