jQuery 實戰讀書筆記之第六章:事件本質

来源:https://www.cnblogs.com/fxb248/archive/2018/02/06/8424739.html
-Advertisement-
Play Games

理解瀏覽器事件模型 understandEventModel.html 代碼: understandEventModel.js: jQuery 事件模型 jQueryEventModel.html: jQueryEventModel.js: ...


理解瀏覽器事件模型

understandEventModel.html 代碼:

<!DOCTYPE HTML>
<html>
    <head>
        <title>Understand Event Model</title>
        <meta charset="UTF-8" />
        <link rel="stylesheet" href="../css/main.css"/>
        <style>
            img
            {
                display: block;
                margin: auto;
            }
        </style>
    </head>
    <body>
        <img id="example" src="images/example.jpg" alt="A bolt of lightning"
            onclick="console.log('At ' + formatDate(new Date()) + ' BOOM!');" />
 
        <p>The output is printed on the console</p>

        <!-- 在 onsubmit 中調用返回 false 的方法不能阻止預設動作 -->
        <!-- <form id="myForm" action="www.cnblogs.com" onsubmit="doSubmit()"> -->
        <form id="myForm" action="www.cnblogs.com" onsubmit="return false">
            <div>
                <label for="name">Name:</label>
                <input id="name" name="name" type="text" />
            </div>
            <div>
                <button type="submit">Click me!</button>
            </div>
        </form>
 
        <form id="myForm2" action="www.cnblogs.com" onsubmit="prevent()">
            <div>
                <label for="name2">Name:</label>
                <input id="name2" name="name2" type="text" />
            </div>
            <div>
                <button type="submit">Click me2!</button>
            </div>
        </form>

        <div id="dom2">
            <button id="multipleButton" type="button">multiple events</button>
        </div>
    
        <div id="firstLevel">
            <div id='secondLevel'>
                <input id="testButton" type="button" value="捕獲和冒泡" />
            </div>
        </div>

        <script src="js/understandEventModel.js"></script>
    </body>
</html>

 

understandEventModel.js:

/*
DOM Level 用來表示實現 W3C DOM 規範的級別要求
DOM Level 0 Event Model,在這個模型背後,事件處理器通過把函數賦值給元素的屬性來聲明實現
*/
function formatDate(date) {
    return (date.getHours() < 10 ? '0' : '') + date.getHours() +
            ':' + (date.getMinutes() < 10 ? '0' : '') + date.getMinutes() +
            ':' + (date.getSeconds() < 10 ? '0' : '') + date.getSeconds() +
            '.' + (date.getMilliseconds() < 10 ? '00' : (date.getMilliseconds() < 100 ? '0' : '')) +
            date.getMilliseconds();
}

/*
id 為 example 的圖片在 HTML 代碼中直接在標簽屬性 onclick 中聲明瞭一個 click 事件,這個屬性值會被使用創建一個
匿名函數體,類似下麵的代碼,直接在標簽屬性中聲明事件不是推薦的做法
*/
document.getElementById('example').onmouseover = function(event) {
    console.log(this);
    console.log('At ' + formatDate(new Date()) + ' Crackle!');

    //當觸發事件處理器時,在所有相容標準的瀏覽器里,一個名為 Event 的對象會作為第一參數傳遞給處理器,只有 IE9 以上,
    //Firefox,Chrome, Safari 和 Opera 支持, IE8 之前的瀏覽器可以通過自己的方式把 Event 對象傳給全局的 event 屬性
    event = event || window.event;

    //獲取目標元素的引用,也就是觸發事件的元素,必須通過相容標準瀏覽器的 target 屬性獲取,但是舊的 IE 使用
    //的是 srcElement
    var target = event.target || event.srcElement;
};

 

/*
事件冒泡
目標元素有機會處理事件之後,瀏覽器的事件處理機制會檢查元素的父元素是否包含此事件類型的處理器,如果有也會調用,再
依次檢查爺爺元素,直到 DOM 樹的頂部
*/
var elements = document.getElementsByTagName('*');  //得到頁面上的所有元素

for(var i = 0; i < elements.length; i++){
    if(elements[i].id != 'example'){
        (function(current){
            current.onclick = function(event){
                event = event || window.event;
                var target = event.target || event.srcElement;

                console.log('At ' + formatDate(new Date()) +
                            ' For ' + current.tagName + '#' + current.id +
                            ' target is ' + target.tagName + '#' + target.id);
            }
        })(elements[i]);
    }
}


/*
要阻止事件的傳播,在現代瀏覽器中可以調用 Event 實例的 stopPropagation() 方法
在舊的 IE 瀏覽器中可以設置 Event 實例的 cancelBubble 屬性為 true 實現,現在很多新的瀏覽器也提供了該屬性,儘管
這不是 W3C 標準(我覺得這個實踐中還是不用的好,知道作用就好)
有些事件是預設動作,比如 form 的 submit,要取消這些語義動作,在新的瀏覽器調用 Event 實例的 preventDefault() 方法。舊的
IE 中沒有此方法,設置 returnValue 屬性的值為 false;另一種方法是處理器代碼返回 false
<form name="myForm" onsubmit="return false;" ... >
*/

/*
被頁面的 onsubmit 屬性引用,但沒有成功阻止預設的 submit 動作
*/
function doSubmit(){
    return false;
}


/*
阻止了預設的 submit 動作
*/
function prevent(){
    event = event || window.event;
    event.preventDefault();
}


/*
DOM Level 2 event model
DOM Level 0 event model 的缺點是每個元素每次只能註冊一種特定類型的事件處理器,主要是因為屬性用來存儲
事件處理器函數的引用
DOM Level 2 event model 就是為瞭解決上面的問題而建立的。這裡的事件處理器通過標準的元素方法而不是元素屬性賦值
來實現,每個 DOM 元素都實現了一個 addEventListener() 方法。
addEventListener(eventType, listener, useCapture)
eventType: 要處理的事件類型,DOM 0 中使用的事件,比如 click
listener:表示元素事件處理器的函數
useCapture:布爾值
*/
var multipleButton = document.getElementById('multipleButton');

/*
這個 multipleButton 按鈕在下麵代碼增加事件處理器之前,上面的代碼中增加了 click 事件是處理函數,從結果可以看出,
這個處理函數有被保留,而且是作為第一個觸發
event.stopPropagation() 隨便寫在哪個處理函數中效果都一樣,不會事件冒泡到父元素
*/
multipleButton.addEventListener('click', function(event){
    console.log('At ' + formatDate(new Date()) + ' BOOM once!');
    //event.stopPropagation();
});

multipleButton.addEventListener('click', function(event){
    console.log('At ' + formatDate(new Date()) + ' BOOM twice!');
    //event.stopPropagation();
});

multipleButton.addEventListener('click', function(event){
    console.log('At ' + formatDate(new Date()) + ' BOOM thrice!');
    event.stopPropagation();
});

 

/*
DOM Level 2 event model 中的事件傳播
事件首先從 DOM 樹根結點向目標元素傳播,然後從目標元素向 DOM 根節點冒泡傳播。前面的階段成為捕獲階段,後者
是冒泡階段

addEventListener(eventType, listener, useCapture) 方法中的 useCapture 是用來標記函數作為何種處理器使用的,false 為
冒泡階段處理器,true 為捕獲階段處理器,預設為 false
*/

/*function eventLog(curElement, event){
    event = event || window.event;
    console.log('At ' + formatDate(new Date()) +
    ' Capture for ' + curElement.tagName + '#' + curElement.id ) +
    ' target is ' + event.target.tagName + '#' +  event.target.id;
}*/

var firstLevel = document.getElementById('firstLevel');
var secondLevel = document.getElementById('secondLevel');
var testButton = document.getElementById('testButton');

firstLevel.onclick = function(){};
secondLevel.onclick = function(){};
testButton.onclick = function(){};

//捕獲階段運行
firstLevel.addEventListener('click', function(event){
    console.log('At ' + formatDate(new Date()) +
    ' Capture for ' + this.tagName + '#' + this.id ) +
    ' target is ' + event.target.tagName + '#' +  event.target.id;
}, true);

firstLevel.addEventListener('click', function(event){
    console.log('At ' + formatDate(new Date()) +
    ' Bubble for ' + this.tagName + '#' + this.id ) +
    ' target is ' + event.target.tagName + '#' +  event.target.id;
}, false);

secondLevel.addEventListener('click', function(event){
    console.log('At ' + formatDate(new Date()) +
    ' Capture for ' + this.tagName + '#' + this.id ) +
    ' target is ' + event.target.tagName + '#' +  event.target.id;
}, true);

secondLevel.addEventListener('click', function(event){
    console.log('At ' + formatDate(new Date()) +
    ' Bubble for ' + this.tagName + '#' + this.id ) +
    ' target is ' + event.target.tagName + '#' +  event.target.id;
}, false);

testButton.addEventListener('click', function(event){
    console.log('At ' + formatDate(new Date()) +
    ' Capture for ' + this.tagName + '#' + this.id ) +
    ' target is ' + event.target.tagName + '#' +  event.target.id;
}, true);

testButton.addEventListener('click', function(event){
    console.log('At ' + formatDate(new Date()) +
    ' Bubble for ' + this.tagName + '#' + this.id ) +
    ' target is ' + event.target.tagName + '#' +  event.target.id;
}, false);

 

jQuery 事件模型

jQueryEventModel.html:

<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8" />
      <title>Events in jQuery Example - jQuery in Action, 3rd edition</title>
      <link rel="stylesheet" href="../css/main.css"/>
      <style>
         img
         {
            display: block;
            margin: auto;
         }
      </style>
   </head>
   <body>
      <img id="example" src="images/example.jpg" alt="A bolt of lightning"/>

      <p>
          <button id="btn1">Click me!</button>
          <button id="btn2">Don't click me!</button>
      </p>

      <ul id="myList"></ul>

      <p>
          <button id="btn">Does nothing</button>
          <button id="btn-attach">Attach handler</button>
          <button id="btn-remove">Remove handler</button>
      </p>

      <p>The output is printed on the console</p>

      <script src="../js/jquery-3.2.1.js"></script>
      <script src="js/jQueryEventModel.js"></script>
   </body>
</html>

 

jQueryEventModel.js:

/*
jQuery Event Model
1. 為創建事件處理器提供統一方法
2. 允許每個元素、每個事件類型註冊多個方法
3. 適用標準事件名稱,如 click 或 mouseover
4. 傳遞 Event 實例作為第一個參數
5. 規範事件實例中最常用的屬性
6. 為事件取消和阻止操作提供統一的方法

除了不支持捕獲階段,jQuery 事件模型幾乎完美支持 DOM Level 2 Event Model
*/

function formatDate(date) {
    return (date.getHours() < 10 ? '0' : '') + date.getHours() +
            ':' + (date.getMinutes() < 10 ? '0' : '') + date.getMinutes() +
            ':' + (date.getSeconds() < 10 ? '0' : '') + date.getSeconds() +
            '.' + (date.getMilliseconds() < 10 ? '00' : (date.getMilliseconds() < 100 ? '0' : '')) +
            date.getMilliseconds();
 }

 /*
on(eventType[, selector][, data], handler)
on(eventHash[, selector][, data])
為選擇的元素的一個或多個事件添加一個或多個事件處理器

eventType(String):事件類型的名稱,多個事件類型可以用空格分隔
selector(String):過濾器用來過濾選中元素的子元素,這些子元素觸發事件
data(Any):傳遞給 Event 實例的數據,賦值給 data 屬性
handler(Function):事件處理器的函數,冒泡階段的當前元素作為函數上下文,false 值表示函數 return false

eventHash(Object):單個調用中為多個事件類型建立處理器的對象。屬性名區分事件類型,屬性值提供事件處理器

返回 jQuery 集合
 */
 $('#example')
         .on('click', function (event) {
            console.log('At ' + formatDate(new Date()) + ' BOOM once!');
         })
         .on('click', function (event) {
            console.log('At ' + formatDate(new Date()) + ' BOOM twice!');
         })
         .on('click', function (event) {
            console.log('At ' + formatDate(new Date()) + ' BOOM thrice!');
         })
         .on('mouseenter mouseleave', function(event){
             console.log(event.type)
         });

$('#btn1').on('click', function(){
    console.log('The button is clicked!');
}).on('mouseenter mouseleave', myFunctionHandler);

/*
使用 eventHash 參數類型的代碼
*/
$('#btn2').on({
    click: function(){
        console.log('Oh no, you clicked me!');
    },
    mouseenter: myFunctionHandler,
    mouseleave: myFunctionHandler
});

function myFunctionHandler(event){
    event.stopPropagation();
    console.log(event.type + ' ' + event.target.id);
}

/*
註意這裡的第二個參數,設置了 data 參數後,可以通過 event 參數的 data 屬性訪問
*/
$('#btn1').on('click', {
    name: 'Martin_Fu'
}, function(event){
    console.log(event.data.name + ' clicked the button!');
});

/*
事件委托(event delegation)
這是一種向元素的父元素添加事件處理器的重要技術,可以為不存在的元素添加事件處理器
*/
$('<li>item1</li>').add($('<li>item2</li>')).appendTo('#myList');
/*
原生 JS 寫法
*/
document.getElementById('myList').addEventListener('click', function(event){
    if(event.target.nodeName === 'LI'){
        console.log('List item: ' + 
            (Array.prototype.indexOf.call(document.getElementById('myList').children, event.target) + 1));
    }
});

/*
這裡註意第二個參數,它會對子元素進行篩選
事件委托的優勢不只局限於為不存在的元素執行事件處理器,更可以節省記憶體和時間。比如 myList 下有很多 <li> ,那麼需要迴圈
添加事件處理器,如果 <li> 元素很多,那麼會耗費不少時間,由於 JS 是單線程的,會導致不好的用戶體驗。
但也不能因為這個原因給一個元素(比如 document )添加過多處理器,同樣影響性能,建議儘可能為離目標元素近的元素添加處理器
*/
$('#myList').on('click', 'li', function(event){
    console.log('List item(jQuery): ' + ($(this).index() + 1));
});


/*
one(eventType[, selector][, data], handler)
one(eventHash[, selector][, data])
為選擇的元素的一個或多個事件添加一個或多個事件處理器,一旦執行,事件處理器會自動刪除

返回 jQuery 集合
 */



/*
off(eventType[, selector][, data], handler)
off(eventHash[, selector][, data])
刪除參數指定的 jQuery 對象中所有元素的事件處理器,如果沒有提供參數,那麼刪除所有的元素處理器

返回 jQuery 集合
 */
/*
這裡註意一點,如果多次點擊 btn-attach 按鈕,btn 按鈕會添加兩個 click 事件,但是只要點擊一次
btn-remove 按鈕,這兩個事件都會移除
*/
var $btn = $('#btn');
var counter = 1;

function logHandler(event){
    console.log('Click ' + counter);
    counter++;
}

$('#btn-attach').on('click', function(event){
    $btn.on('click', logHandler).text('Log');
});

$('#btn-remove').on('click', function(event){
    $btn.off('click', logHandler).text('Does nothing');
});

 


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

-Advertisement-
Play Games
更多相關文章
  • iOS操作系統4層結構,如下表 1、Cocoa Touch是可觸摸層,這一層為我們的應用程式開發提供了各種有用的框架,並且大部分與用戶界面有關,本質上來說它負責用戶在iOS設備上的觸摸交互操作。 包括Address Book UI Framework、Event Kit UI Framework、G ...
  • ...
  • 類型轉換通常是指變數,從一種類型轉換成另外一種類型。例如將一個long類型轉換成int類型,變數轉換通常 用下麵的方式: 在Objective-C中,我們通常使用CGFloat來做浮點運算,32位是float類型,64位是double類型,通常轉換方式 如下操作: 上面代碼編譯執行後的結果: 這裡說 ...
  • 1 View BreakPoints(Ctrl+Shift+F8) (圖3.6.1) 點擊箭頭指向的按鈕,會彈出一個視窗,如下圖。 (圖3.6.2) 在這裡可以查看設置過的所有斷點(箭頭所指)。另外,還可以在這裡設置條件斷點,日誌斷點,異常斷點等,這些高級技巧我們將在本系列的下篇文章里介紹,敬請期待 ...
  • Masonry 實現動畫效果如下: 重點說明: ...
  • Xcode Xcode 工程設置支持 bash 腳本及其語法,如 $(PROJECT_DIR)$(PROJECT_DIR) PROJECT_DIR 代表當前工程的絕對路徑,所以 $(PROJECT_DIR)/../ 代表工程路徑的上一級 $(TARGET_NAME) 目標工程名稱 $(SRCROOT ...
  • UIGestureRecognizer 對iOS的各種手勢進行了封裝,完全滿足了用戶對手勢的需求。 以下是對各種手勢的詳細應用和說明,希望能對大家有幫助。^_^ ...
  • 本篇項目地址,求starhttps://github.com/979451341/Audio-and-video-learning-materials/tree/master/FFmpeg%E6%92%AD%E6%94%BE%E8%A7%86%E9%A2%91首先FFmpeg是c語言寫的,所以我們需 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...