DOM事件處理機制學習筆記

来源:https://www.cnblogs.com/chinaontology/archive/2022/05/02/16213592.html
-Advertisement-
Play Games

DOM 事件是處理 Web 頁面交互的基礎,是掌握前端開發技術的基礎。 W3C協會早在1988年就開始了DOM標準的制定,W3C DOM標準可以分為DOM1,DOM2,DOM3三個版本。 1.Html事件處理 原始事件模型,事件處理程式被設置為html控制項的性質值,一般是html控制項的 onclic ...


DOM 事件是處理 Web 頁面交互的基礎,是掌握前端開發技術的基礎。
W3C協會早在1988年就開始了DOM標準的制定,W3C DOM標準可以分為DOM1,DOM2,DOM3三個版本。

1.Html事件處理

原始事件模型,事件處理程式被設置為html控制項的性質值,一般是html控制項的 onclick、onerror、onload ....
如:

<button type="button" onclcik="console.log('Hello Console!')">ShowConsole</button>
<button type="button" onclick="showFn()">ShowFn</button>
<script>
    function showFn() {
        alert('Hello World');
    }
</script>

優點:
簡單快速,此時代碼的作用域是文檔全局,可以直接使用文檔所有公共變數

缺點:
1、是HTML於JS 強耦合,綁定在一起
2、一個處理程式無法同時綁定多個處理函數
3、執行時機問題:可能會出現 html 上已經顯示控制項,但是關聯的函數還未載入進來,此時用戶點擊,就會執行失敗(你沒辦法告知用戶要等一會兒...)
4、不同瀏覽器對此方式綁定的函數的作用域解釋可能有差異,在部分情況下會導致不同的行為

2.DOM0級事件

就是先取得控制項變數,然後給變數的事件處理程式賦予一個函數,解綁事件處理是將事件處理程式賦為 null

<input id="x1" type="text" value="World!">
<script>
    var x1 = document.getElementById('x1'); 
    x1.onclick = function() {
        alert('Hello World'+this.value);
    } 
    // x1.onclick = null; 解綁事件 
</script>

特點

  • 此方式添加的代碼是註冊在冒泡階段的
  • 此方式添加的函數是元素的屬性,作用域是元素範圍,可以引用元素的屬性(使用 this 代表元素本身)

3.DOM2級事件

DOM級別1於1998年10月1日成為W3C推薦標準。1級DOM標準中並沒有定義事件相關的內容,所以沒有所謂的1級DOM事件模型。

在2級DOM中除了定義了一些DOM相關的操作之外還定義了一個事件模型。當事件發生在節點時,目標元素的事件處理函數就被觸發,而且目標的每個祖先節點也有機會處理那個事件。

DOM事件流包括兩個階段:
1.capturing 消息捕獲階段,事件從Document對象沿著文檔樹向下傳播給節點。如果目標的任何一個祖先專門註冊了事件監聽函數,那麼在事件傳播的過程中就會運行這些函數。
2.下一個階段發生在目標節點自身,直接註冊在目標上的適合的事件監聽函數將運行。
3.bubbling 消息冒泡階段,這個階段事件將從目標元素向上傳播回Document對象(與capturing相反的階段)。雖然所有事件都受capturing階段的支配,但並不是所有類型的事件都bubbling。(0級DOM事件模型處理沒有capturing階段)

老版本的瀏覽器不支持消息捕獲階段的處理。一般都只需要處理消息冒泡階段的事件。

如果想在事件發生前捕獲,然後阻止預設動作發生,可以指定事件處理程式在捕獲階段運行。

所謂事件冒泡就是事件像泡泡一樣從最開始生成的地方一層一層往上冒,一層一層向上直至最外層的html或document。

<div id="box">
    <a id="child">事件冒泡</a>
</div>
<script>
 var box = document.getElementById('box'),
 child = document.getElementById('child');
 
 child.addEventListener('click', function() {
 alert('我是目標事件');
 }, false);
 
 box.addEventListener('click', function() {
 alert('事件冒泡至DIV');
 }, false);
</script>

上面的代碼運行後我們點擊a標簽,首先會彈出’我是目標事件’提示,然後又會彈出’事件冒泡至DIV’的提示,這便說明瞭事件自內而外向上冒泡了。

DOM2級標準中,事件定義了addEventListener和removeEventListener兩個方法,分別用來綁定和解綁事件。

方法中包含3個參數,分別是:
(1)綁定的事件處理屬性名稱(不包含on)
(2)處理函數
(3)是否在捕獲時執行,省略此參數時,預設為false,表示僅在冒泡階段處理

DOM2級事件允許給一個處理程式添加多個處理函數。代碼如下:

<button id="btn" type="button"></button>
<script>
    var btn = document.getElementById('btn');
    function showFn() {
        alert('Hello World');
    }
    btn.addEventListener('click', showFn, false);
    btn.addEventListener('mouseover', showFn, false); // 添加一個滑鼠移入的方法
    // btn.removeEventListener('click', showFn, false); 解綁事件 
</script>

如果是 IE8 以下需要用attachEvent和detachEvent來實現

btn.attachEvent('onclick', showFn); // 綁定事件 
btn.detachEvent('onclick', showFn); // 解綁事件
\\ 這裡我們不需要傳入第三個參數,因為IE8級以下版本只支持冒泡型事件。

4.事件對象

DOM當中發生事件時,所有信息都會被收集並存儲到一個event對象當中
可以在調試台查看 event 對象的結構

let btn = document.getElementById('mybtn');
btn.onclick = function(event){
  console.log(event);
}
btn.addEventListener("click",(event)=>{
  console.log(event);
  // event.stopPropagation();  
  // 加上上面這一句,則按鈕以上層次的就監聽不到 click 事件了,事件冒泡被終止
});
document.body.onclick = (event)=>{
  console.log(event);
}

event對象有一些重要屬性,以下是必須牢記的:

  • type 代表事件類型,例如:click、mouseover...
  • target 代表事件的目標控制項
  • currentTarget 代表事件監聽者控制項,等於 this
  • eventPhase 事件處理程式的階段:1.捕獲 2.到達目標 3.冒泡階段
  • shiftKey bool類型,發生事件時 shift 鍵是否按下
  • ctrlKey bool類型,發生事件時 ctrl 鍵是否按下
  • altKey bool類型,發生事件時 Alt 鍵是否按下
    還有一些方法:
  • stopPropagation 方法:取消事件冒泡
  • preventDefault 方法:阻止預設事件的發生

在上面的代碼當中,點擊按鈕 btn 監聽click 事件,輸出的結果中 event 的 target、currentTarget 都等於 this,就是按鈕對象自身;
但在頁面的 body 的監聽當中,接收到的 event 當中,currentTarget 和 this 代表 body,target 當表點擊發生的真正對象 btn

// 採用 preventDefault 方法,阻止超鏈接的預設動作
let link = document.getElementById("mylink");
link.onclick = (event){
  // 此處可以加上 用戶狀態判斷...
  event.preventDefault();
}

採用 event 的 type 屬性,可以簡化事件處理函數

let btn = document.getElementById("mybtn");
let handler = (event)=>{
  switch(event.type){
    case "click":
      console.log("clicked");
      break;
    case "mouseover":
      console.log("mouseover");
      break;
    default:
      console.log(event.type);
      break;
  }
}
btn.onclick = handler;
btn.onmouseover = handler;

5.DOM3級事件

DOM3級事件在DOM2級事件的基礎上添加了更多的事件類型,全部類型如下:

UI事件,當用戶與頁面上的元素交互時觸發,如:load、unload、scroll
焦點事件,當元素獲得或失去焦點時觸發,如:blur、focus
滑鼠事件,當用戶通過滑鼠在頁面執行操作時觸發如:dbclick、mouseup
滾輪事件,當使用滑鼠滾輪或類似設備時觸發,如:mousewheel
文本事件,當在文檔中輸入文本時觸發,如:textInput
鍵盤事件,當用戶通過鍵盤在頁面上執行操作時觸發,如:keydown、keypress
合成事件,當為IME(輸入法編輯器)輸入字元時觸發,如:compositionstart,compositionupdate,compositionend
變動事件,當底層DOM結構發生變化時觸發,如:DOMsubtreeModified
同時DOM3級事件也允許使用者自定義一些事件。

一些常用的事件:

// load:頁面載入事件
window.addEventListener("load",(event)=>{
  console.log("html文檔已經載入完畢");      
});

// DOMContentLoaded: 網頁DOM樹構建完成後觸發,並不等待圖像等附加資源完成

// beforeunload:可以發生在網頁內容卸載之前,可以阻止(例如要求用戶進行保存)
window.addEventListener("beforeunload",(event)=>{
  console.log("文檔保存...");  
});

// unload:可以發生在網頁導航,載入新網頁時, 舊內容已經卸載
window.addEventListener("unload",(event)=>{
  console.log("文檔已經卸載...");  
});

// error:添加全局錯誤的監聽,如果頁面內圖像未載入成功,就將圖像替換為另一張圖像
window.addEventListener("error",(event)=>{
          console.log('body knows:',event);
      console.log(event.target.tagName);
      if (event.target.tagName=="IMG"){
          console.log(event.target);
          event.target.src = 'img/404.jpg';
      }
  },true);

// resize:視窗縮放事件
window.addEventListener("resize",(event)=>{
        console.log("height=",window.innerHeight);
    console.log("width=",window.innerWidth);
});

// textInput:監聽輸入內容
// textInput 不同於 keyPress,只監聽輸入區內容,且可以通過 event.data 獲得輸入的內容
let myTxt = document.getElementById("myInput");
    myTxt.addEventListener("textInput",(event)=>{
    console.log(event.data);
    if (event.data=="yyds"){
        event.target.value = event.target.value.replace(event.data,"永遠的神");
    }
});

6.時鐘事件

setTimeout函數,可以利用系統時鐘,創建一個被時鐘喚醒的函數,來執行功能;
setInterval函數,可以利用系統時鐘,創建一個以固定間隔執行任務的程式。

// 創建一個5秒鐘以後執行的程式
let timer1 = setTimeout(()=>{ console.log('一次性任務');},5000);
// 如果在timer1執行前調用此函數,可以取消時鐘任務
function killTimer(){
    clearTimeout(timer1);
}

// 創建每秒報時的報時器
let timer2 = setInterval(()=>{
  console.log(new Date());
},1000);
// 清除報時器
function killInteTimer(){
   clearTimeout(timer2);
}

7.SPA應用中的事件處理框架

為了避免在html控制項上直接添加事件處理程式與監聽程式,避免複雜凌亂的事件函數,避免html與JS代碼的混合,以及避免執行時機、記憶體泄露等問題,
可以利用 DOM 事件機制,利用事件捕獲以及事件冒泡,在 DOM 的頂層節點上添加事件監聽處理函數,將用戶交互事件處理入口歸併到一處。
主要原理是,在需要交互的控制項上添加自定義屬性,並賦值,在DOM頂層監聽中,利用截獲的 event.target 獲得事件發生的控制項,
利用控制項的 attributes 數組獲得自定義屬性的值,以這些值作為參數,用於事件處理函數。

// 以下程式中,控制項上添加了 ele_type 自定義屬性
// Html控制項  
<span id="lab_username" ele_type="username" ele_data="Bruce">精思入神</button>
<p ele_type="userinfo">這個用戶剛剛註冊,還沒有填寫個人信息</p>

// 統一的處理入口
document.addEventListener('click',function(event){
    let t = event.target;
    if (!t.attributes.ele_type){
        return;
    }
    let type = t.attributes.ele_type.value;
    if (type=="username"){
        console.log("username clicked!")
        let userid = t.attributes.ele_data.value;
        console.log(userid); // 輸出 Bruce
    }
    if (type=="userinfo"){
        console.log("userinfo clicked!")
    }
})

8.事件模擬

可以利用代碼模擬事件。可以用在程式邏輯需要的地方,不需要用戶動作,自動提供事件

let btn = document.getElementById("mybtn");
// 創建事件
let m_event = document.createEvent("MouseEvents");
// 初始化為滑鼠click事件
m_event.initMouseEvent("click",true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);
// 通過 btn 按鈕發送出去(此 event 的target自動賦值為當前按鈕)
btn.dispatchEvent(m_event);

9.用戶自定義事件

利用用戶自定義事件,可以在控制項、模塊之間傳遞消息,不用在模塊之間直接函數調用,可以讓相互調用更加靈活。

// 自定義事件
let div = document.getElementById('myInput');
// 定義用戶自定義事件監聽程式,app_event 是自己定義的全新消息類型
div.addEventListener("app_event",(event)=>{
    console.log(event.detail);
});
// 激發用戶自定義事件
function sendAppEvent(){
    if (document.implementation.hasFeature("CustomEvents","3.0")){
        event = document.createEvent("CustomEvent");
        event.initCustomEvent('app_event',true,false,'Hello App!');
        div.dispatchEvent(event);
    }
}

參考文獻:


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 基於 OpenAtom OpenHarmony(以下簡稱“OpenHarmony”)源碼寫點內容,幫助大家瞭解下協議開發領域,儘可能將 3gpp 協議內容與 OpenHarmony 電話子系統模塊進行結合講解。 ...
  • 變聲是直播類、聊天類應用中用戶經常使用的功能。例如:很多主播選擇使用變聲器來實現帶動直播間氣氛;和朋友語音聊天時選擇變成蘿莉音讓聊天更有趣。HMS Core音頻編輯服務提供變聲能力,幫助開發者在應用中構建變聲功能。用戶可以通過預置的變聲風格進行變聲,提升音頻可玩性的同時有效保護用戶隱私,讓你隨心所欲 ...
  • 技術大咖們從開源實戰項目總結經驗,利用真實場景的應用案例分享前沿技術,引導開發者從零參與 OpenHarmony 開源貢獻,提升代碼效率,培養開發者成為開源社區的貢獻者。 ...
  • 1. 準備階段 關於該功能的實現我們需要學習以下的資料: 1.1 【ARKUI】ets怎麼實現文件操作 1.2 文件管理 1.3 Ability上下文 2. demo 實現 2.1 文件路徑讀取 參考 context.getFilesDir 來進行獲取文件路徑,代碼如下 private getCac ...
  • 今天做了一個案例,可以好好做做能夠將之前的內容結合起來,最主要的是能對組件化編碼流程有一個大概的清晰認知,這一套做下來,明天自己再做一遍複習一下,其實組件化流程倒是基本上沒什麼問題了,主要是很多vue的方法需要多熟悉一下,畢竟打破了之前的一些對於傳統js的認知,還需要多熟悉一下。 這兩天可能內容不是 ...
  • 大家好,我是半夏👴,一個剛剛開始寫文的沙雕程式員.如果喜歡我的文章,可以關註➕ 點贊 👍 加我微信:frontendpicker,一起學習交流前端,成為更優秀的工程師~關註公眾號:搞前端的半夏,瞭解更多前端知識! 點我探索新世界! 原文鏈接 ==>http://sylblog.xin/archi ...
  • 一、主要區別 1、{} 和 new Object() 除了本身創建的對象,都繼承了 Object 原型鏈上(Object.prototype)的屬性或者方法,eg:toString();當創建的對象相同時,可以說 {} 等價於 new Object() 。2、Object.create() 是將創建 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 1. 非同步編程的實現方式? JavaScript中的非同步機制可以分為以下幾種: 回調函數 的方式,使用回調函數的方式有一個缺點是,多個回調函數嵌套的時候會造成回調函數地獄,上下兩層的回調函數間的代碼耦合度太高,不利於代碼的可維護。 Pro ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...