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
  • 前言 本文將以 C# 語言來實現一個簡單的布隆過濾器,為簡化說明,設計得很簡單,僅供學習使用。 感謝@時總百忙之中的指導。 布隆過濾器簡介 布隆過濾器(Bloom filter)是一種特殊的 Hash Table,能夠以較小的存儲空間較快地判斷出數據是否存在。常用於允許一定誤判率的數據過濾及防止緩存 ...
  • 目錄 一.簡介 二.效果演示 三.源碼下載 四.猜你喜歡 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 轉場 零基礎 O ...
  • 「簡單有價值的事情長期堅持做」 這是成功最簡單,但也最難學的秘訣。不經過訓練,人很難意識到時間複利的威力。 仙劍奇俠傳的「十里坡劍神」和金庸群俠傳的「十級野球拳」,就是簡單的事情持之以恆反覆做,最後就有巨大的威力 唐家三少成為網文收入第一,最重要的一步是十四年從未斷日更 這樣的案例很多,一開始可能成 ...
  • 迎面走來了你的面試官,身穿格子衫,挺著啤酒肚,髮際線嚴重後移的中年男子。 手拿泡著枸杞的保溫杯,胳膊夾著MacBook,MacBook上還貼著公司標語:“我愛加班”。 面試開始,直入正題。 面試官: 看你簡歷上面寫著精通MySQL,我先問你事務的特性是什麼? 老生常談,這個還有誰不會背的嗎? 我: ...
  • 基礎知識 python是一門腳本語言,它是解釋執行的。 python使用縮進做為語法,而且python2環境下同一個py文件中不能同時存在tab和空格縮進,否則會出錯,建議在IDE中顯示縮進符。 python在聲明變數時不寫數據類型,可以type(xx)來獲取欄位的類型,然後可以int(),list ...
  • 為什麼要多線程下載 俗話說要以終為始,那麼我們首先要明確多線程下載的目標是什麼,不外乎是為了更快的下載文件。那麼問題來了,多線程下載文件相比於單線程是不是更快? 對於這個問題可以看下圖。 橫坐標是線程數,縱坐標是使用對應線程數下載對應文件時花費的時間,藍橙綠代表下載文件的大小,每個線程下載對應文件2 ...
  • 詳細講解python爬蟲代碼,爬微博搜索結果的博文數據。 爬取欄位: 頁碼、微博id、微博bid、微博作者、發佈時間、微博內容、轉發數、評論數、點贊數。 爬蟲技術: 1、requests 發送請求 2、datetime 時間格式轉換 3、jsonpath 快速解析json數據 4、re 正則表達式提... ...
  • 背景: 一般我們可以用HashMap做本地緩存,但是HashMap功能比較弱,不支持Key過期,不支持數據範圍查找等。故在此實現了一個簡易的本地緩存,取名叫fastmap。 功能: 1.支持數據過期 2.支持等值查找 3.支持範圍查找 4.支持key排序 實現思路: 1.等值查找採用HashMap2 ...
  • 目錄 一.簡介 二.效果演示 三.源碼下載 四.猜你喜歡 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 轉場 零基礎 O ...
  • 本章是系列文章的第八章,用著色演算法進行寄存器的分配過程。 本文中的所有內容來自學習DCC888的學習筆記或者自己理解的整理,如需轉載請註明出處。周榮華@燧原科技 寄存器分配 寄存器分配是為程式處理的值找到存儲位置的問題 這些值可以存放到寄存器,也可以存放在記憶體中 寄存器更快,但數量有限 記憶體很多,但 ...