1)事件監聽
什么是“事件監聽”
DOM允許我們書寫JavaScript代碼以讓HTML元素對事件作出反應,
什么是“事件”:用戶與網頁的互動動作
- 當用戶點擊元素時
- 當滑鼠移動到元素上時
- 當文本框的內容被改變時
- 當鍵盤在文本框中被按下時
- 當網頁已加載完畢時
- ……
- “監聽”,顧名思義,就是讓計算機隨時能夠發現這個事件發生了,從而執行程式員預先撰寫的一些程式,
- 設定事件監聽的方法主要有onxxx和addEventListener()兩種,
最簡單的設定事件監聽的方法
- 最簡單的給元素設定事件監聽的方法就是設定它們的onxxx屬性,像這樣:
常見的滑鼠事件監聽
事件名
事件描述
onclick
當滑鼠單擊某個物件
ondblclick
當滑鼠雙擊某個物件
onmousedown
當某個滑鼠按鍵在某個物件上被按下
onmouseup
當某個滑鼠按鍵在某個物件上被松開
onmousemove
當某個滑鼠按鍵在某個物件上被移動
onmouseenter
當滑鼠進入某個物件(相似事件onmouseover)
onmouseleave
當滑鼠離開某個物件(相似事件onmouseout)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> #box1 { width: 300px; height: 300px; background-color: #000; } </style> </head> <body> <div id="box1"></div> <script> var box1 = document.getElementById('box1'); // 當滑鼠單擊某個物件 box1.onclick = function() { console.log('滑鼠單擊'); } // 當滑鼠雙擊某個物件 box1.ondblclick = function() { console.log('滑鼠雙擊'); } // 當某個滑鼠按鍵在某個物件上被按下 box1.onmousedown = function() { console.log('滑鼠被按下'); } // 當某個滑鼠按鍵在某個物件上被松開 box1.onmouseup = function() { console.log('滑鼠被松開'); } // 當某個滑鼠按鍵在某個物件上被移動 box1.onmousemove = function() { console.log('滑鼠被移動'); } // 當滑鼠進入某個物件(相似事件onmouseover) box1.onmouseenter = function() { console.log('滑鼠進入'); } // 當滑鼠離開某個物件(相似事件onmouseout) box1.onmouseleave = function() { console.log('滑鼠離開'); } </script> </body> </html>
常見的鍵盤事件監聽
事件名
事件描述
onkeypress
當某個鍵盤的鍵被按下(系統按鈕如箭頭鍵和功能鍵無法得到識別)
onkeydown
當某個鍵盤的鍵被按下(系統按鈕可以識別,并且會先于onkeypress發生)
onkeyup
當某個鍵盤的鍵被松開
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <input type="text" id="box1"><br><br> <input type="text" id="box2"> <script> var box1 = document.getElementById('box1'); var box2 = document.getElementById('box2'); // 當某個鍵盤的鍵被按下(系統按鈕如箭頭鍵和功能鍵無法得到識別) box1.onkeypress = function() { console.log('鍵盤的鍵被按下,但不包括系統按鈕'); } // 當某個鍵盤的鍵被按下(系統按鈕可以識別,并且會先于onkeypress發生) box2.onkeydown = function() { console.log('鍵盤的鍵被按下,包括系統按鈕'); } // 當某個鍵盤的鍵被松開 box1.onkeyup = function() { console.log('鍵盤的鍵被松開'); } box2.onkeyup = function() { console.log('鍵盤的鍵被松開'); } </script> </body> </html>
常見的表單事件監聽
事件名
事件描述
onchange
當用戶改變域的內容
onfocus
當某元素獲得焦點(比如tab鍵或滑鼠點擊)
onblur
當某元素失去焦點
onsubmit
當表單被提交
onreset
當表單被重置
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <form id="myform"> <p> 姓名: <input type="text" name="nameField"> </p> <p> <input type="submit"> </p> <p> <input type="reset"> </p> </form> <script> var myform = document.getElementById('myform'); var nameField = myform.nameField; nameField.onchange = function() { console.log('你已經修改完了姓名'); } nameField.oninput = function() { console.log('你正在修改姓名'); } nameField.onfocus = function() { console.log('姓名框已經得到了焦點'); } nameField.onblur = function() { console.log('姓名框已經失去了焦點'); } myform.onsubmit = function() { alert('你正在嘗試提交表單'); } myform.onreset = function() { alert('你正在嘗試重置表單'); } </script> </body> </html>
常見的頁面事件監聽
事件名
事件描述
onload
當頁面或影像被完成加載
onunload
當用戶退出頁面
2)事件傳播
- 實際上,事件的傳播是:先從外到內,然后再從內到外,
- onxxx這樣的寫法只能監聽冒泡階段,
addEventListener()方法
- DOM0級事件監聽:只能監聽冒泡階段,
- DOM2級事件監聽:
注意事項
- 最內部元素不再區分捕獲和冒泡階段,會先執行寫在前面的監聽,然后執行后寫的監聽,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> #box1 { width: 202px; height: 202px; border: 1px solid #000; padding: 50px; } #box2 { width: 100px; height: 100px; border: 1px solid #000; padding: 50px; } #box3 { width: 100px; height: 100px; border: 1px solid #000; } </style> </head> <body> <div id="box1"> <div id="box2"> <div id="box3"></div> </div> </div> <script> var oBox1 = document.getElementById('box1'); var oBox2 = document.getElementById('box2'); var oBox3 = document.getElementById('box3'); oBox2.addEventListener('click', function() { console.log('我是box2的冒泡階段'); }, false); oBox3.addEventListener('click', function() { console.log('我是box3的捕獲階段'); }, true); oBox3.addEventListener('click', function() { console.log('我是box3的冒泡階段'); }, false); oBox3.onclick = function() { console.log('我是box3的onclick'); }; oBox1.addEventListener('click', function() { console.log('我是box1的冒泡階段'); }, false); oBox2.addEventListener('click', function() { console.log('我是box2的捕獲階段'); }, true); oBox1.addEventListener('click', function() { console.log('我是box1的捕獲階段'); }, true); oBox1.onclick = function() { console.log('我是box1的onclick'); }; oBox2.onclick = function() { console.log('我是box2的onclick'); }; </script> </body> </html>
- 如果給元素設定相同的兩個或多個同名事件,則DOM0級寫法后面寫的會覆寫先寫的;而DOM2級會按順序執行,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> #box2 { width: 100px; height: 100px; border: 1px solid #000; padding: 50px; } </style> </head> <body> <div id="box2"></div> <script> var oBox2 = document.getElementById('box2'); oBox2.onclick = function() { console.log('A'); }; oBox2.onclick = function() { console.log('B'); }; oBox2.addEventListener('click', function() { console.log('C'); }, false); oBox2.addEventListener('click', function() { console.log('D'); }, false); </script> </body> </html>
3)事件物件
什么是事件物件
- 事件處理函式提供一個形式引數,它是一個物件,封裝了本次事件的細節,
- 這個引數通常用單詞event或字母e來表示,
滑鼠位置
屬性
屬性描述
clientX
滑鼠指標相對于瀏覽器的水平坐標
clientY
滑鼠指標相對于瀏覽器的垂直坐標
pageX
滑鼠指標相對于整張網頁的水平坐標
pageY
滑鼠指標相對于整張網頁的垂直坐標
offsetX
滑鼠指標相對于事件源元素的水平坐標
offsetY
滑鼠指標相對于事件源元素的垂直坐標
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } #box { width: 200px; height: 200px; background-color: #333; margin: 100px; } body { height: 2000px; } #info { font-size: 30px; } </style> </head> <body> <div id="box"></div> <div id="info"></div> <script> var oBox = document.getElementById('box'); var oInfo = document.getElementById('info'); oBox.onmousemove = function(e) { oInfo.innerHTML = 'offsetX/Y: ' + e.offsetX + ',' + e.offsetY + '<br><br>' + 'clientX/Y: ' + e.clientX + ',' + e.clientY + '<br><br>' + 'pageX/Y: ' + e.pageX + ',' + e.pageY; } </script> </body> </html>
e.charCode和e.keyCode屬性
- e.charCode屬性通常用于onkeypress事件中,表示用戶輸入的字符的“字符碼”,
字符
字符碼
數字0 ~ 數字9
48 ~ 57
大寫字母A ~ Z
65 ~ 90
小寫字母a ~ z
97 ~ 122
- e.keyCode屬性通常用于onkeydown事件和onkeyup中,表示用戶按下的按鍵的“鍵碼”,
按鍵
鍵碼
數字0 ~ 數字9
48 ~ 57(同charCode鍵碼完全相同)
字母不分大小a ~ z
65 ~ 90(同charCode鍵碼的大寫字母A ~ Z,而keyCode不分大小寫,一律為65 ~ 90)
四個方向鍵← ↑ → ↓
37,38,39,40
回車鍵
13
空格鍵
32
小案例
- 制作一個特效:按方向鍵可以控制頁面上的盒子移動,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> #box { position: absolute; top: 200px; left: 200px; width: 100px; height: 100px; background-color: gold; } </style> </head> <body> <div id="box"></div> <script> var oBox = document.getElementById('box'); // 全域變數t、l,分別表示盒子的top屬性值和left屬性值 var t = 200; var l = 200; // 監聽document物件的鍵盤按下事件監聽,表示當用戶在整個網頁上按下按鍵的時候 document.onkeydown = function(e) { switch (e.keyCode) { case 37: // 左 l -= 6; break; case 38: // 上 t -= 6; break; case 39: // 右 l += 6; break; case 40: // 下 t += 6; break; } // 更改樣式 oBox.style.left = l + 'px'; oBox.style.top = t + 'px'; } </script> </body> </html>
e.preventDefault()方法
- e.preventDefault()方法用來阻止事件產生的“默認動作”,
- 一些特殊的業務需求,需要阻止事件的“默認動作”,
小案例1
- 制作一個文本框,只能讓用戶在其中輸入小寫字母和數字,其他字符輸入沒有效果,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <p> 只能輸入小寫字母和數字: <input type="text" id="field"> </p> <script> var oField = document.getElementById('field'); oField.onkeypress = function(e) { // 根據用戶輸入的字符的字符碼(e.charCode) // 數字0~9,字符碼48~57 // 小寫字母a~z,字符碼97~122 if (!(e.charCode >= 48 && e.charCode <= 57 || e.charCode >= 97 && e.charCode <= 122)) { // 阻止瀏覽器的默認行為 e.preventDefault(); // 輸出無法輸入字符的字符碼 console.log(e.charCode); } } </script> </body> </html>
小案例2
- 制作滑鼠滾輪事件:當滑鼠在盒子中向下滾動時,數字加1;反之,數字減1 ,
- 滑鼠滾輪事件是onmousewheel,它的事件物件e提供deltaY屬性表示滑鼠滾動方向,向下滾動時回傳正值,向上滾動時回傳負值,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> #box { width: 200px; height: 200px; background-color: #333; } body { height: 2000px; } </style> </head> <body> <div id="box"></div> <h1 id="info">0</h1> <script> var oBox = document.getElementById('box'); var oInfo = document.getElementById('info'); // 全域變數就是info中顯示的數字 var a = 0; // 給box盒子添加滑鼠滾輪事件監聽 oBox.onmousewheel = function(e) { // 阻止默認事件:就是說當用戶在盒子里面滾動滑鼠滾輪的時候,此時不會引發頁面的滾動條的滾動 e.preventDefault(); if (e.deltaY > 0) { a++; } else if (e.deltaY < 0) { a--; } oInfo.innerText = a; } </script> </body> </html>
e. stopPropagation()方法
- e.stopPropagation()方法用來阻止事件繼續傳播,
- 在一些場合,非常有必要切斷事件繼續傳播,否則會造成頁面特效顯示出bug,
小案例
- 制作一個彈出層:點擊按鈕顯示彈出層,點擊網頁任意地方,彈出層關閉,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .modal { width: 400px; height: 140px; background-color: #333; position: absolute; top: 50%; left: 50%; margin-top: -70px; margin-left: -200px; display: none; } </style> </head> <body> <button id="btn">按我彈出彈出層</button> <div class="modal" id="modal"></div> <script> var oBtn = document.getElementById('btn'); var oModal = document.getElementById('modal'); // 點擊按鈕的時候,彈出層顯示 oBtn.onclick = function(e) { // 阻止事件繼續傳播到document身上 e.stopPropagation(); oModal.style.display = 'block'; } // 點擊頁面任何部分的時候,彈出層關閉 document.onclick = function() { oModal.style.display = 'none'; } // 點擊彈出層內部的時候,不能關閉彈出層的,所以應該阻止事件繼續傳播 oModal.onclick = function(e) { e.stopPropagation(); oModal.style.display = 'block'; } </script> </body> </html>
4)事件委托
批量添加事件監聽
- 題目:頁面上有一個無序串列<ul>,它內部共有10個<li>元素,請批量給它們添加點擊事件監聽,實作效果:點擊哪個<li>元素,哪個<li>元素就變紅,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <ul id="list"> <li>串列項</li> <li>串列項</li> <li>串列項</li> <li>串列項</li> <li>串列項</li> <li>串列項</li> <li>串列項</li> <li>串列項</li> <li>串列項</li> <li>串列項</li> </ul> <script> var oList = document.getElementById('list'); var lis = oList.getElementsByTagName('li'); // 書寫回圈陳述句,批量給元素添加監聽 for (var i = 0; i < lis.length; i++) { lis[i].onclick = function() { // 在這個函式中,this表示點擊的這個元素 this.style.color = 'red'; }; } </script> </body> </html>
批量添加事件監聽的性能問題
- 每一個事件監聽注冊都會消耗一定的系統記憶體,而批量添加事件會導致監聽數量太多,記憶體消耗會非常大,
- 實際上,每個<li>的事件處理函式都是不同的函式,這些函式本身也會占用記憶體,
新增元素動態系結事件
- 題目:頁面上有一個無序串列<ul>,它內部沒有<li>元素,請制作一個按鈕,點擊這個按鈕就能增加一個<li>元素,并且要求每個增加的<li>元素也要有點擊事件監聽,實作效果點擊哪個<li>元素,哪個<li>元素就變紅,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <button id="btn">按我添加新的li串列項</button> <ul id="list"></ul> <script> var oBtn = document.getElementById('btn'); var oList = document.getElementById('list'); var lis = oList.getElementsByTagName('li'); // 按鈕的點擊事件 oBtn.onclick = function () { // 創建一個新的li串列項,孤兒節點 var oLi = document.createElement('li'); oLi.innerHTML = '我是串列項'; // 上樹 oList.appendChild(oLi); // 給新創建的這個li節點添加onclick事件監聽 oLi.onclick = function () { this.style.color = 'red'; }; }; </script> </body> </html>
動態系結事件的問題
- 新增元素必須分別添加事件監聽,不能自動獲得事件監聽,
- 大量事件監聽、大量事件處理函式都會產生大量消耗記憶體,
事件委托
- 利用事件冒泡機制,將后代元素事件委托給祖先元素,
e.target和e.currentTarget屬性
- 事件委托通常需要結合使用e.target屬性,
屬性
屬性描述
target
觸發此事件的最早元素,即“事件源元素”
currentTarget
事件處理程式附加到的元素
事件委托的使用場景
- 當有大量類似元素需要批量添加事件監聽時,使用事件委托可以減少記憶體開銷,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <ul id="list"> <li>串列項</li> <li>串列項</li> <li>串列項</li> <li>串列項</li> <li>串列項</li> <li>串列項</li> <li>串列項</li> <li>串列項</li> <li>串列項</li> <li>串列項</li> </ul> <script> var oList = document.getElementById('list'); oList.onclick = function(e) { // e.target表示用戶真正點擊的那個元素 e.target.style.color = 'red'; } </script> </body> </html>
- 當有動態元素節點上樹時,使用事件委托可以讓新上樹的元素具有事件監聽,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <button id="btn">按我創建一個新串列項</button> <ul id="list"></ul> <script> var oList = document.getElementById('list'); var oBtn = document.getElementById('btn'); oList.onclick = function(e) { // e.target表示用戶真正點擊的那個元素 e.target.style.color = 'red'; }; oBtn.onclick = function() { // 創建新的li元素 var oLi = document.createElement('li'); // 寫內容 oLi.innerText = '我是新來的'; // 上樹 oList.appendChild(oLi); }; </script> </body> </html>
使用事件委托時需要注意的事項
- onmouseenter和onmouseover都表示“滑鼠進入”,它們有什么區別呢?
- 答:onmouseenter不冒泡,onmouseover冒泡,
- 使用事件委托時要注意:不能委托不冒泡的事件給祖先元素,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <ul id="list1"> <li>串列1</li> <li>串列1</li> <li>串列1</li> </ul> <ul id="list2"> <li>串列2</li> <li>串列2</li> <li>串列2</li> </ul> <script> var oList1 = document.getElementById('list1'); var oList2 = document.getElementById('list2'); // oList1使用onmouseenter不冒泡 oList1.onmouseenter = function(e) { // e.target表示用戶真正點擊的那個元素 e.target.style.color = 'red'; } // oList2使用onmouseover冒泡 oList2.onmouseover = function(e) { // e.target表示用戶真正點擊的那個元素 e.target.style.color = 'red'; } </script> </body> </html>
- 最內層元素不能再有額外的內層元素了,比如:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <ul id="list"> <li><span>我是span</span>串列項</li> <li><span>我是span</span>串列項</li> <li><span>我是span</span>串列項</li> </ul> <script> var oList = document.getElementById('list'); oList.onclick = function(e) { // e.target表示用戶真正點擊的那個元素 e.target.style.color = 'red'; } </script> </body> </html>
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/301063.html
標籤:其他
上一篇:定時器 防抖 節流
下一篇:取消當前請求-vue




















