一、註冊事件(綁定事件)
1.1註冊事件概述
給元素添加事件,稱爲註冊事件或者綁定事件。
註冊事件有兩種方式:傳統方式和方法監聽註冊方式。
傳統註冊方式
- 利用on開頭事件onclick
- 特點:註冊事件的唯一性
- 同一個元素同一個事件只能設置一個處理函數,最後註冊的處理函數將會覆蓋前面註冊的處理函數。
方法監聽註冊方式
- W3C標準推薦方式
- addEventListener()它是一個方法
- IE9之前的IE不支持此方法,可以使用attachEvent()代替
- 特點:同一個元素同一個事件可以註冊多個監聽器
- 按照註冊事件依次執行
1.2addEventListener事件監聽方式
eventTarget.addEventListener(type, listener[, useCapture])
eventTarget.addEventListener()方法將指定的監聽器註冊到eventrarget (目標對象)上,當該對
象觸發指定的事件時,就會執行事件處理函數。
該方法接收三個參數:
- type :事件類型字符串,比如click、mouseover , 注意這裏不要帶on
- listener :事件處理函數,事件發生時,會調用該監聽函數
- useCapture: 可選參數,是-個布爾值,默認是false
1.3attachEvent 事件監聽方式(IE9以下)
eventTarget . att achEvent (eventNamewi thon,callback)
eventrarget . attachEvent ()方法將指定的監聽器註冊到eventrarget (目標對象)上,當該對象觸
髮指定的事件時,指定的回調函數就會被執行。
該方法接收兩個參數:
- eventNameWithOn :事件類型字符串,比如onclick. onmouseover, 這裏要帶 on
- callback :事件處理函數,當目標觸發事件時回闊函數被調用
1.4註冊事件兼容性解決方案
function addEventListener (element, eventName, fn) {
//判斷當前瀏覽器是否支持addEventListener方法
if (element.addEventListener) {
element.addEventListener (eventName, fn); // 第三個參數默認是false
} else if (element.attachEvent) {
element.attachEvent('on' + eventName,fn);
} else {
//相當於element .οnclick= fn;
element[ 'on' + eventName] = fn;
}
}
<!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>註冊事件</button>
<button>方法監聽註冊事件</button>
<button>IE9</button>
<script>
//1.傳統方式註冊事件
var btns = document.querySelectorAll('button');
btns[0].onclick = function() {
alert('hi');
}
btns[0].onclick = function() {
alert('hello');
}
//2.事件偵聽註冊事件 addEventListener裏面的事件類型是字符串 必定加引號 而且不帶on
btns[1].addEventListener('click', function() {
alert(22);
})
btns[1].addEventListener('click', function() {
alert(33);
})
//3.attachEvent ie9以前版本
btns[2].attachEvent('onclick', function() {
alert(11);
})
</script>
</body>
</html>
二、刪除事件
2.2刪除事件的方式
1.傳統註冊方式
eventTarget.onclick = null;
2.方法監聽註冊方式
eventTarget.removeEventListener(Type, listener[, useCapture])
<!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>
div {
width: 100px;
height: 100px;
background-color: pink;
}
</style>
</head>
<body>
<div>1</div>
<div>2</div>
<div>3</div>
</body>
<script>
var divs = document.querySelectorAll('div');
divs[0].onclick = function() {
alert(11);
//1.傳統方式刪除事件
divs[0].onclick = null;
}
//2.removeEventListener 刪除事件
divs[1].addEventListener('click', fn); //裏面的fn不需要調用加小括號
function fn() {
alert(22);
divs[1].removeEventListener('click', fn);
}
//3.
divs[3].attachEvent('onclick', fn1);
function fn1() {
alert(33);
div[2].detattachEvent('onclick', fn1);
}
</script>
</html>
三、DOM事件流
事件流描述的是從頁面中接收事件的順序
事件發生時會在元素節點之間按照待定的順序傳播,這個傳播過程即DOM事件流
DOM事件流分爲3個階段:
1.捕獲階段
2.當前目標階段
3.冒泡階段
事件冒泡:IE最早提出,事件開始時由最具體的元素接收,然後逐級向上傳播到DOM最頂層節點的過程
事件捕獲:網景最早提出,由DOM最頂層節點開始,然後逐級向下傳播到最具體的元素接收過程
注意:
(1)JS代碼中只能執行捕獲或者冒泡其中的一個階段
(2)onclick和attachEvent只能得到冒泡階段
(3)addEventListener(type, listener, [, useCapture])第三個參數如果是true,表示在事件捕獲階段調用事件處理程序,如果是false(不寫就默認爲false),表示在事件冒泡階段調用事件處理程序。
(4)實際開發中我們很少使用捕獲事件,我們更關注事件冒泡
(5)有些事件是沒有冒泡的,比如onblur、onfocus、onmouseenter、onmouseleave
<!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>
.father {
overflow: hidden;
width: 400px;
height: 400px;
margin: 100px auto;
background-color: pink;
text-align: center;
}
.son {
width: 300px;
height: 300px;
margin: 50px;
background-color: purple;
line-height: 300px;
color: #fff;
}
</style>
</head>
<body>
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
//捕獲階段 如果 addEventListener 第三個參數是 true 那麼處於捕獲階段
//body -> father -> son
// var son = document.querySelector('.son');
// son.addEventListener('click', function() {
// alert('son');
// }, true);
// var father = document.querySelector('.father');
// father.addEventListener('click', function() {
// alert('father');
// }, true);
//冒泡階段
var son = document.querySelector('.son');
son.addEventListener('click', function() {
alert('son');
});
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
});
document.addEventListener('click', function() {
alert('document');
})
</script>
</body>
</html>
四、事件對象
4.1什麼是事件對象?
eventTarget. onclick = function (event) {}
eventTarget . addEventListener(‘click’, function(event) {})
這個event就是事件對象,我們還喜歡的寫成e或者evt
官方解釋: event對象代表事件的狀態,比如鍵盤按鍵的狀態鼠標的位置、鼠標按鈕的狀態。
**簡單理解:**事件發生後,跟事件相關的一系列信息數據的集合都放到這個對象裏面,這個對象就是事件對象event ,它有很多屬性和方法。
比如:①誰綁定了這個事件②鼠標觸發事件的話,會得到鼠標的相關信息,如鼠標位置③鍵盤觸發事件的話,會得到鍵盤的相關信息,如按了哪個鍵
這個event是個形參,系統幫我們設定爲事件對象,不需要傳遞實參過去,當我們註冊事件時,event對象就會被系統自動創建,並依次傳遞給事件監聽器(事件處理函數)
4.2事件對象兼容性方案
事件對象本身的獲取存在兼容問題:
1.標準瀏覽器中是瀏覽器給方法傳遞的參數,只需要定義形參e就可以獲取到。
2.在IE6~8中,瀏覽器不會給方法傳遞參數,如果需要的話,窩要到window.event中獲取查找。
<!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>
<div>123</div>
<script>
//1.event就是一個事件對象 寫到我們偵聽函數的小括號裏 當形參來看
//2.事件對象只有有了事件纔會存在,它是系統給我們自動創建的 不需要我們傳遞參數
//3.事件對象是我們事件的一系列相關數據的集合 跟事件相關的 比如鼠標點擊裏面就包含了鼠標的相關信息,
//鼠標座標,如果是鍵盤事件裏面就包含的鍵盤事件的信息 比如判斷用戶按下了哪個鍵
//4.這個事件對象我們可以自己命名 比如 event evt e
//5.事件對象也有兼容性問題 IE678通過window.event
var div = document.querySelector('div');
// div.onclick = function(event) {
// console.log(event);
// }
div.addEventListener('click', function(e) {
console.log(e);
})
</script>
</body>
</html>
4.3事件對象的常見屬性和方法
五、阻止冒泡事件
5.1阻止事件冒泡的兩種方式
事件冒泡:開始時由最具體的元素接收,然後逐級向上傳播到DOM的最頂層節點
阻止事件冒泡
- 標準寫法:利用事件對象裏面的stopPropagation()方法
- 非標準寫法:IE 678利用事件對象cancelBubble屬性
5.2阻止事件冒泡的兼容性解決方案
if (e && e.stopPropagation){
e.stopPropagation;
}else{
window.event.cancelBubble = true;
}
<!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>
.father {
overflow: hidden;
width: 400px;
height: 400px;
margin: 100px auto;
background-color: pink;
text-align: center;
}
.son {
width: 300px;
height: 300px;
margin: 50px;
background-color: purple;
line-height: 300px;
color: #fff;
}
</style>
</head>
<body>
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
//捕獲階段 如果 addEventListener 第三個參數是 true 那麼處於捕獲階段
//body -> father -> son
// var son = document.querySelector('.son');
// son.addEventListener('click', function() {
// alert('son');
// }, true);
// var father = document.querySelector('.father');
// father.addEventListener('click', function() {
// alert('father');
// }, true);
//冒泡階段
var son = document.querySelector('.son');
son.addEventListener('click', function(e) {
alert('son');
e.stopPropagation();
e.cancelBubble = true;
});
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
});
document.addEventListener('click', function() {
alert('document');
})
//兼容性解決方案
// if (e && e.stopPropagation){
// e.stopPropagation;
// }else{
// window.event.cancelBubble = true;
// }
</script>
</body>
</html>
六、事件委託(代理、委託)
事件委託
事件委託也稱爲事件代理,在jQuery裏面稱爲事件委派
事件委託的原理
不是每個子節點單獨設置事件監聽器,而是事件監聽器設置在其父節點上,然後利用冒泡原理影響設置每個子節點
事件委託作用
我們只操作了一次DOM,提高了程序的性能
<!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>
<li>彈框</li>
<li>彈框</li>
<li>彈框</li>
<li>彈框</li>
<li>彈框</li>
</ul>
<script>
var ul = document.querySelector('ul');
var lis = document.querySelectorAll('li');
ul.addEventListener('click', function(e) {
// alert('彈框');
for (var i = 0; i < lis.length; i++) {
lis[i].style.backgroundColor = '';
e.target.style.backgroundColor = 'pink';
}
})
</script>
</body>
</html>
七、常用的鼠標事件
7.1常用的鼠標事件
1.禁止鼠標右鍵菜單
contextmenu主要控制應該何時顯示上下文菜單,主要用於程序員取消默認的上下文菜單
document.addEventListener('contextmenu', function(e){
e.preventDefault();
})
2.禁止鼠標選中(selectstart 開始選中)
<!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>
我是一段不願意分享的文字
<script>
//1.contextmenu 我們可以禁用右鍵菜單
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
})
//2.禁止選中文字
document.addEventListener('selectstart', function(e) {
e.preventDefault();
})
</script>
</body>
</html>
7.2鼠標事件對象
<!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>
body {
height: 3000px;
}
</style>
</head>
<body>
<script>
//鼠標事件對象MouseEvent
document.addEventListener('click', function(e) {
//1.client 鼠標在可視區的x和y座標
console.log(e.clientX);
console.log(e.clientY);
console.log('……………………………………………………');
//2.page 鼠標在頁面文檔的x和y座標
console.log(e.pageX);
console.log(e.pageY);
})
</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>
<style>
img {
position: absolute;
top: 2px;
}
</style>
</head>
<body>
<img src="angel.gif" alt="">
<script>
var pic = document.querySelector('img')
document.addEventListener('mousemove', function(e) {
//1.mousemove 只要我們鼠標移動1px 就會觸發這個事件
// console.log(1);
var x = e.pageX;
var y = e.pageY;
console.log('X座標是' + x, 'Y座標是' + y);
//不要忘記添加px 單位
pic.style.left = x - 50 + 'px';
pic.style.top = y - 40 + 'px';
});
</script>
</body>
</html>
八、常用的鍵盤事件
8.1常用鍵盤事件
事件除了使用鼠標觸發,還可以使用鍵盤觸發
注意:
1.如果使用addEventLiatener不需要加on
2.onkeypress 不識別功能鍵 ,比如 左右箭頭 shift等
3.三個事件的執行順序:keydown > keypress >keyup
<!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>
<script>
//1.keyup按鍵彈起的時候觸發
// document.onkeyup = function() {
// console.log('我彈起了');
// }
//2.keydown 按鍵按下的時候觸發
// document.addEventListener('keydown', function() {
// console.log(1111);
// })
//3.keypress 按鍵按下的時候觸發 不能識別功能鍵
document.addEventListener('keypress', function() {
console.log(2222);
})
//4.三個事件的執行順序 keydown > keypress >keyup
</script>
</body>
</html>
8.2鍵盤事件對象
注意:onkeyup和onkeydown事件不區分字母大小寫,onkeypress區分字母大小寫
在我們實際開發中,我們更多使用keydown和keyup,它能識別所有的鍵(包括功能鍵)
keypress不識別功能鍵,但是keyCode屬性能區分大小寫,返回不同的ASCII值
<!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>
<script>
//鍵盤事件對象中的keycode屬性可以得到相應鍵的ASCII碼值
//1.我們的keyup和keydown事件不區分字母大小寫 a和A得到的都是65
//2.我們的keypress事件區分字母大小寫 a 97和 A 65
document.addEventListener('keyup', function(e) {
// console.log(e);
console.log('up:' + e.keyCode);
//我們可以利用keycode返回的ASCII碼值來判斷用戶按下了哪個鍵
if (e.keyCode === 65) {
alert('你按下的a鍵');
} else {
alert('你沒有按下a鍵');
}
})
document.addEventListener('keypress', function(e) {
// console.log(e);
console.log('press:' + e.keyCode);
})
</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>
<input type="text">
<script>
var search = document.querySelector('input');
document.addEventListener('keyup', function(e) {
// console.log(e.keyCode);
if (e.keyCode === 83) {
search.focus();
}
})
</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>
<style>
.search {
position: relative;
width: 178px;
margin: 100px;
}
.con {
display: none;
position: absolute;
top: -40px;
width: 171px;
border: 1px solid rgb(0, 0, 0, .2);
box-shadow: 0 2px 4px rgb(0, 0, 0, .2);
padding: 5px 0;
font-size: 18px;
line-height: 20px;
color: #333;
}
.con::before {
content: '';
width: 0;
height: 0;
position: absolute;
top: 28px;
left: 18px;
border: 8px solid #000;
border-style: solid dashed dashed;
border-color: #fff transparent transparent;
}
</style>
</head>
<body>
<div class="search">
<div class="con">123</div>
<input type="text" placeholder="請輸入你的快遞單號" class="jd">
</div>
<script>
var con = document.querySelector('.con');
var jd_input = document.querySelector('.jd');
jd_input.addEventListener('keyup', function() {
if (this.value == '') {
con.style.display = 'none';
} else {
con.style.display = 'block';
con.innerHTML = this.value;
}
//當我們失去焦點 隱藏con盒子
jd_input.addEventListener('blur', function() {
con.style.display = 'none';
})
//當我們獲得焦點 顯示con盒子
jd_input.addEventListener('focus', function() {
if (this.value != 0) {
con.style.display = 'block';
}
})
})
</script>
</body>
</html>