DOM 事件機制

DOM 事件機制

  • 事件是元素天生具有的行爲方式(和寫不寫 JS 代碼不要緊),當咱們去操做元素的時候會觸發元素的不少事件
  • 給當前元素的某一個事件綁定方法,目的是爲了讓當前元素某個事件被觸發的時候,能夠作一些事情

DOM0 事件

DOM0 事件綁定javascript

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

element.onmouseenter=function(){}
  • 給當前元素對象的某一個私有屬性(onxxx 這樣的私有屬性)賦值的過程(以前屬性默認值是 null,若是咱們給賦值一個函數,至關於綁定了一個方法)
  • 當賦值成功(賦值一個函數),此時瀏覽器會把 DOM 元素和賦值的函數創建關聯,以及創建 DOM 元素行爲操做的監聽,當某一個行爲被用戶觸發,瀏覽器會把相關行爲賦值的函數執行
  • 一、只有 DOM 元素天生擁有這個私有屬性(onxxx 事件私有屬性),咱們賦值的方法才叫作事件綁定,不然屬於給當前元素設置一個自定義屬性而已
  • 二、移除事件綁定的時候,咱們只須要賦值爲 null 便可
  • 三、在 DOM0 事件綁定中,只能給當前元素的某一個事件行爲(某一個事件私有屬性)綁定一個方法,綁定多個方法,最後一次綁定的會把以前綁定的都替換掉
btn.onclick = function() {
  console.log("this is a click event");
};

click 事件並無像其餘函數同樣,必需要調用才能夠執行,click 事件並不肯定何時發生,而當瀏覽器發現用戶點擊該按鈕時,瀏覽器就檢測 btn.onclick 是否有值,若是有,就會執行 btn.onclick.call(btn,event),此時函數執行,call() 方法接收兩個參數,第一個指向調用當前方法的對象,也就是 thishtml

須要注意的是,指定的 this 值並不必定是該函數執行時真正的 this 值,若是這個函數處於非嚴格模式下,則指定爲 nullundefinedthis 值會自動指向全局對象(瀏覽器中就是 window 對象),同時值爲原始值(數字,字符串,布爾值)的 this 會指向該原始值的自動包裝對象。java

另外一個參數則是事件對象 event,該對象也能夠經過 arguments[0] 來訪問,它包含了事件相關的全部信息,如本例子中,則包含了點擊事件的所有信息。能夠經過給函數傳參來獲取事件信息。node

btn.onclick = function(e) {
  console.log("this is a click event");
  console.log(e); //  事件對象
};

在 DOM0 級中,若是想要實現一個對象綁定多個函數,能夠這樣實現。git

function fn1() {
  // do something
}
function fn2() {
  // do something
}
btn.onclick = function(e) {
  fn1.call(this, xxx);
  fn2.call(this, yyy);
};
https://github.com/HarleyWang...

DOM2 事件

當前這個實例 document.body 之因此能用 addEventListener 這個方法,說明這個方法確定在它的原型上出現。github

能夠用 instanceof 檢測瀏覽器

DOM2 級事件定義了兩個方法,用於處理指定和刪除事件處理程序的操做,addEventListener()removeEventListener(),全部的 DOM 節點中都包含這兩個方法,它們都接收 3 個參數dom

  • 要處理的事件名
  • 做爲事件處理程序的函數
  • 布爾值,true 表明在捕獲階段調用事件處理程序,false 表示在冒泡階段調用事件處理程序,默認爲 false
btn.addEventListener("click", function() {
  //  do something
});
btn.addEventListener("click", function() {
  //  do something else
});
element.addEventListener(
  "click",
  function(event) {
    // 只執行一次的代碼
  },
  { once: true }
);
  • 一、 DOM2 事件綁定使用的 addEventListener/attachEvent 都是在 EventTarget 這個內置類的原型上定義的,調取使用的時候,首先經過原型鏈找到這個方法,而後執行完成事件綁定的效果
  • 瀏覽器首先會給當前元素的某一個事件行爲開闢一個事件池(事件隊列)[實際上是瀏覽器有一個統一的事件池,咱們每一個元素的某個行爲綁定的方法都放在這個事件池中,只是經過相關的標識來區分的],當咱們經過 addEventListener 作事件監聽的時候,會把綁定的方法存放在事件池中
  • 當元素的某一個行爲觸發,瀏覽器會到對應的事件池中,把當前存放在事件池中的全部方法,依次按照存放的前後順序執行

DOM0 是私有屬性賦值,DOM2 是事件池的事件機制編輯器

  • 一、全部 DOM0 支持的事件行爲,DOM2 均可以使用,不只如此,DOM2 還支持一些 DOM0 沒有的事件行爲:DOMContentLoaded...
  • 二、DOM2 中能夠給當前元素的某一個事件行爲綁定‘多個不一樣的方法’(不一樣的方法=>不一樣的空間地址,好比一個私有 fn 和全局的 fn 地址不同,因此不是同一個 fn 方法,)(由於綁定的全部方法都存放在事件池中了;而 DOM0 是經過給私有屬性賦值來綁定方法的,一個私有屬性只能附一個值)
  • 三、DOM2 事件綁定的移除比較麻煩一些,須要和綁定的時候:事件類型、綁定的方法、傳播階段,三個徹底一致才能夠移除掉

DOM3 事件

DOM3 級事件在 DOM2 級事件的基礎上添加了更多的事件類型,所有類型以下函數

事件類型 說明 舉例
UI 事件 當用戶與頁面上的元素交互時觸發 {load、scroll
焦點事件 當元素得到或失去焦點時觸發 blur、focus
鼠標事件 當用戶經過鼠標在頁面執行操做時觸發 dbclick、mouseup
滾輪事件 當使用鼠標滾輪或相似設備時觸發 mousewheel
文本事件 當在文檔中輸入文本時觸發 textInput
鍵盤事件 當用戶經過鍵盤在頁面上執行操做時觸發 keydown、keypress
合成事件 當爲 IME(輸入法編輯器)輸入字符時觸發 compositionstart
變更事件 當底層 DOM 結構發生變化時觸發 DOMsubtreeModified

同時 DOM3 級事件也容許開發人員自定義一些事件。

var event = new Event('build');

// Listen for the event.
elem.addEventListener('build', function (e) { ... }, false);

// Dispatch the event.
elem.dispatchEvent(event);

添加自定義數據 – CustomEvent()

var event = new CustomEvent("build", { detail: elem.dataset.time });

冒泡事件&捕獲事件

img

事件委託

因爲事件會在冒泡階段向上傳播到父節點,所以能夠把子節點的監聽函數定義在父節點上,由父節點的監聽函數統一處理多個子元素的事件。這種方法叫作事件的代理(delegation

那麼利用事件冒泡或捕獲的機制,能夠對事件綁定作一些優化。 在 JS 中,若是咱們註冊的事件愈來愈多,頁面的性能就愈來愈差,由於:

  • 函數是對象,會佔用內存,內存中的對象越多,瀏覽器性能越差
  • 註冊的事件通常都會指定 DOM 元素,事件越多,致使 DOM 元素訪問次數越多,會延遲頁面交互就緒時間。
  • 刪除子元素的時候不用考慮刪除綁定事件
<ul id="list">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
</ul>

<script>
// 給父層元素綁定事件
document.getElementById('list').addEventListener('click', function (e) {
    // 兼容性處理
    var event = e || window.event;
    var target = event.target || event.srcElement;
    // 判斷是否匹配目標元素
    if (target.nodeName.toLocaleLowerCase() === 'li') {
        console.log('the content is: ', target.innerHTML);
    }
});
</script>

EventTarget

DOM 的事件操做(監聽和觸發),都定義在 EventTarget 接口。全部節點對象都部署了這個接口,其餘一些須要事件通訊的瀏覽器內置對象(好比,XMLHttpRequestAudioNodeAudioContext)也部署了這個接口

該接口主要提供三個實例方法。

  • addEventListener:綁定事件的監聽函數;用於在當前節點或對象上,定義一個特定事件的監聽函數。一旦這個事件發生,就會執行監聽函數。該方法沒有返回值。
  • removeEventListener:移除事件的監聽函數;方法用來移除 addEventListener 方法添加的事件監聽函數;removeEventListener 方法的參數,與 addEventListener 方法徹底一致
  • dispatchEvent:觸發事件;當前節點上觸發指定事件,從而觸發監聽函數的執行。該方法返回一個布爾值,只要有一個監聽函數調用了 Event.preventDefault(),則返回值爲 false,不然爲 true;參數是 Event 實例

Event 對象常見的方法和屬性

  • event. preventDefault();若是調用這個方法,默認事件行爲將再也不觸發。什麼是默認事件呢?例如表單一點擊提交按鈕(submit)刷新頁面、a 標籤默認頁面跳轉或是錨點定位等
  • event.stopPropagation() & event.stopImmediatePropagation() event.stopPropagation() 方法阻止事件冒泡到父元素,阻止任何父事件處理程序被執行; stopImmediatePropagation 既能阻止事件向父元素冒泡,也能阻止元素同事件類型的其它監聽器被觸發。而 stopPropagation 只能實現前者的效果
https://juejin.im/post/5be643...

https://www.w3.org/TR/DOM-Lev...

https://javascript.ruanyifeng...

https://javascript.ruanyifeng...

相關文章
相關標籤/搜索