事件
- addEventListener 用來處理多個事件同時綁定
element.addEventListener(event, handler[, options]);
handler 事件處理程序, event 事件對象,handleEvent 對象處理程序
冒泡和捕獲
- 冒泡
當一個事件發(fā)生在一個元素上蹲缠,它會首先運行在該元素上的處理程序费就,然后運行其父元素上的處理程序咖城,然后一直向上到其他祖先上的處理程序
- event.target
引發(fā)事件的那個嵌套層級最深的元素被稱為目標元素,可以通過 event.target 訪問
停止冒泡
event.stopPropagation()用于停止冒泡
event.stopImmediatePropagation() 用于停止冒泡十绑,并阻止當前元素上的處理程序運行。使用該方法之后慧瘤,其他處理程序就不會被執(zhí)行
捕獲
DOM事件標準描述了事件傳播的 3 個階段:
- 捕獲階段(Capturing phase)—— 事件(從 Window)向下走近元素戴已。
- 目標階段(Target phase)—— 事件到達目標元素。
- 冒泡階段(Bubbling phase)—— 事件從元素上開始冒泡锅减。
如果要在捕獲階段捕獲事件 糖儡,需要將處理程序的 capture選項設置為 true
ele.addEventListener(..., {capture: true})
ele.addEventListener(..., true)
事件委托
如果我們有許多以類似方式處理的元素,那么就不必為每個元素分配一個處理程序 —— 而是將單個處理程序放在它們的共同祖先上
- 行為模式
- 行為: 計數器
var btn = document.querySelector("button");
var num = 0;
btn.onclick = function (){
btn.innerHTML = ++num;
if(btn.innerText == 10){
alert("不累么怔匣?握联?")
btn.style.background = "orange";
}
}
- 行為:切換器
<div class="wrapper">
<button data-toggle-id="changeBox">點擊切換</button>
<div id="changeBox"></div>
</div>
<script>
let btn = document.querySelector('button')
btn.addEventListener('click', function(event){
let id = event.target.dataset.toggleId;
if(!id) return
let ele = document.querySelector('#'+id)
ele.style.display == 'none' ?
ele.style.display = 'block':
ele.style.display = 'none'
})
</script>
瀏覽器默認行為
event.preventDefault() 用于阻止默認行為,如果處理程序是使用 on<event>(而不是 addEventListener)分配的,那返回 false 也同樣有效
創(chuàng)建自定義事件
- 事件構造器
let event = new Event(type[,options])
type —— 事件類型拴疤,可以是像這樣 "click" 的字符串永部,或者我們自己的像這樣 "my-event" 的參數
options —— 具有兩個可選屬性的對象:默認情況下独泞,以上兩者都為 false:{bubbles: false, cancelable: false}
- 觸發(fā)
通過使用 elem.dispatchEvent(event)調用在元素上“運行” - 其他一些事件
● UIEvent
● FocusEvent
● MouseEvent
● WheelEvent
● KeyboardEvent
let event = new MouseEvent("click", {
bubbles: true,
cancelable: true,
clientX: 100,
clientY: 100
});
- 自定義事件
<h1 id="elem">Hello for John!</h1>
<script>
// 事件附帶給處理程序的其他詳細信息
elem.addEventListener("hello", function(event) {
alert(event.detail.name);
});
elem.dispatchEvent(new CustomEvent("hello", {
detail: { name: "John" }
}));
</script>
鼠標事件
- 鼠標事件類型
mousedown / mouseup
在元素上點擊/釋放鼠標按鈕
mouseover / mouseout
鼠標指針從一個元素上移入/移出
mousemove
鼠標在元素上的每個移動都會觸發(fā)此事件
click
果使用的是鼠標左鍵呐矾,則在同一個元素上的 mousedown 及 mouseup 相繼觸發(fā)后,觸發(fā)該事件
dblclick
在短時間內雙擊同一元素后觸發(fā)
contextmenu
在鼠標右鍵被按下時觸發(fā)
事件順序
在單個動作觸發(fā)多個事件時懦砂, 事件的順序是固定的蜒犯,會遵循 mousedown -> mouseup -> click 的順序調用處理程序-
鼠標按鈕
使用 button 屬性來區(qū)分是左鍵單擊還是右鍵單擊
組合鍵: shift、alt荞膘、ctrl罚随、meta
事件屬性:
● shiftKey:Shift
● altKey:Alt(或對于 Mac 是 Opt)
● ctrlKey:Ctrl
● metaKey:對于 Mac 是 Cmd坐標: clientX/Y, pageX/Y
- 相對于窗口的坐標:clientX 和 clientY。
- 相對于文檔的坐標:pageX 和 pageY
-
防止在鼠標按下時的選擇
防止瀏覽器對 mousedown進行操作羽资,可以阻止鼠標按下時的選擇
Before...
<b ondblclick="alert('Click!')" onmousedown="return false">
Double-click me
</b>
...After
通過使用oncopy事件淘菩, 可以防止用戶復制
<div oncopy="alert('Copying forbidden!');return false">
Dear user,
The copying is forbidden for you.
If you know JS or HTML, then you can get everything from the page source though.
</div>
移動鼠標: mouseover/out , mouseenter/leave
-
事件mouseover/mouseout, relatedTarget
當鼠標指針移到某個元素上時屠升,mouseover 事件就會發(fā)生潮改,而當鼠標離開該元素時,mouseout 事件就會發(fā)生
對于mouseover:
● event.target —— 是鼠標移過的那個元素腹暖。
● event.relatedTarget —— 是鼠標來自的那個元素(relatedTarget → target) -
跳過元素
注意: 如果 mouseover被觸發(fā)了汇在, 則必須有 mouseout -
事件 mouseenter和mouseleave
事件 mouseenter/mouseleave 類似于 mouseover/mouseout。它們在鼠標指針進入/離開元素時觸發(fā)
- 元素內部與后代之間的轉換不會產生影響脏答。
- 事件 mouseenter/mouseleave 不會冒泡糕殉。
鼠標拖放事件
- 拖放算法
- 在 mousedown 上 —— 根據需要準備要移動的元素(也許創(chuàng)建一個它的副本,向其中添加一個類或其他任何東西)
- 然后在 mousemove 上殖告,通過更改 position:absolute 情況下的 left/top 來移動它
- 在 mouseup 上 —— 執(zhí)行與完成的拖放相關的所有行為
ball.onmousedown = function(event) {
// (1) 準備移動:確保 absolute阿蝶,并通過設置 z-index 以確保球在頂部
ball.style.position = 'absolute';
ball.style.zIndex = 1000;
// 將其從當前父元素中直接移動到 body 中
// 以使其定位是相對于 body 的
document.body.append(ball);
// 現在球的中心在 (pageX, pageY) 坐標上
function moveAt(pageX, pageY) {
ball.style.left = pageX - ball.offsetWidth / 2 + 'px';
ball.style.top = pageY - ball.offsetHeight / 2 + 'px';
}
// 將我們絕對定位的球移到指針下方
moveAt(event.pageX, event.pageY);
function onMouseMove(event) {
moveAt(event.pageX, event.pageY);
}
// (2) 在 mousemove 事件上移動球
document.addEventListener('mousemove', onMouseMove);
// (3) 放下球,并移除不需要的處理程序
ball.onmouseup = function() {
document.removeEventListener('mousemove', onMouseMove);
ball.onmouseup = null;
};
};
為防止瀏覽器自己的拖放處理與我們的拖放處理產生沖突黄绩,需禁用它
ball.ondragstart = function() {
return false;
};
- 修正定位
ball.onmousedown = function(event) {
let shiftX = event.clientX - ball.getBoundingClientRect().left;
let shiftY = event.clientY - ball.getBoundingClientRect().top;
ball.style.position = 'absolute';
ball.style.zIndex = 1000;
document.body.append(ball);
moveAt(event.pageX, event.pageY);
// 移動現在位于坐標 (pageX, pageY) 上的球
// 將初始的偏移考慮在內
function moveAt(pageX, pageY) {
ball.style.left = pageX - shiftX + 'px';
ball.style.top = pageY - shiftY + 'px';
}
function onMouseMove(event) {
moveAt(event.pageX, event.pageY);
}
// 在 mousemove 事件上移動球
document.addEventListener('mousemove', onMouseMove);
// 放下球羡洁,并移除不需要的處理程序
ball.onmouseup = function() {
document.removeEventListener('mousemove', onMouseMove);
ball.onmouseup = null;
};
};
ball.ondragstart = function() {
return false;
};
-
潛在的放置目標
有一個叫做 document.elementFromPoint(clientX, clientY) 的方法。它會返回在給定的窗口相對坐標處的嵌套的最深的元素(如果給定的坐標在窗口外宝与,則返回 null)
基于 onMouseMove 擴展的代碼焚廊,用于查找 “droppable” 的元素
// 我們當前正在飛過的潛在的 droppable 的元素
let currentDroppable = null;
function onMouseMove(event) {
moveAt(event.pageX, event.pageY);
ball.hidden = true;
let elemBelow = document.elementFromPoint(event.clientX, event.clientY);
ball.hidden = false;
// mousemove 事件可能會在窗口外被觸發(fā)(當球被拖出屏幕時)
// 如果 clientX/clientY 在窗口外,那么 elementfromPoint 會返回 null
if (!elemBelow) return;
// 潛在的 droppable 的元素被使用 "droppable" 類進行標記(也可以是其他邏輯)
let droppableBelow = elemBelow.closest('.droppable');
if (currentDroppable != droppableBelow) {
// 我們正在飛入或飛出...
// 注意:它們兩個的值都可能為 null
// currentDroppable=null —— 如果我們在此事件之前习劫,鼠標指針不是在一個 droppable 的元素上(例如空白處)
// droppableBelow=null —— 如果現在咆瘟,在當前事件中,我們的鼠標指針不是在一個 droppable 的元素上
if (currentDroppable) {
// 處理“飛出” droppable 的元素時的處理邏輯(移除高亮)
leaveDroppable(currentDroppable);
}
currentDroppable = droppableBelow;
if (currentDroppable) {
// 處理“飛入” droppable 的元素時的邏輯
enterDroppable(currentDroppable);
}
}
}
鍵盤: keydown 和 keyup
當一個按鍵被按下時诽里,會觸發(fā)keydown事件袒餐,而當按鍵被釋放時,會觸發(fā)keyup事件。
注意: event.code 和 event.key
事件對象的 key 屬性允許獲取字符灸眼,而事件對象的 code 屬性則允許獲取“物理按鍵代碼”
滾動
-
防止?jié)L動
只能在 pageUp和pageDown的 keydown事件上卧檐, 使用event.preventDefault() 來阻止?jié)L動
表單屬性和方法
-
導航: 表單和元素
文檔中的表單是特殊集合 document.forms 的成員 -
input和textarea
通過 input.value(字符串)或 input.checked(布爾值)來訪問復選框(checkbox)中的它們的 value
聚焦: focus / blur
-
focus/blur 事件
當元素聚焦時,會觸發(fā)focus事件焰宣,當元素失去焦點時霉囚,會觸發(fā)blur事件 -
focus/blur方法
elem.focus() 和 elem.blur() 方法可以設置和移除元素上的焦點 - 允許在任何元素上聚焦: tabindex
點擊第一項,然后按 Tab 鍵匕积。跟蹤順序盈罐。請注意,多按幾次 Tab 鍵后闪唆,會將焦點移到這個通過 iframe 嵌入的示例的外面盅粪。
<ul>
<li tabindex="1">One</li>
<li tabindex="0">Zero</li>
<li tabindex="2">Two</li>
<li tabindex="-1">Minus one</li>
</ul>
<style>
li { cursor: pointer; }
:focus { outline: 1px dashed green; }
</style>
-
focus/blur 委托
focus 和 blur 事件不會向上冒泡。
使用 focusin 和 focusout 事件 —— 與 focus/blur 事件完全一樣悄蕾,只是它們會冒泡票顾。
值得注意的是,必須使用 elem.addEventListener 來分配它們帆调,而不是 on<event>
表單事件: change奠骄, input, cut贷帮, copy戚揭, paste
-
事件: change
當元素更改完成時, 將觸發(fā)change事件
<input type="text" onchange="alert(this.value)">
-
事件: input
每當用戶對輸入值進行修改后撵枢, 就會觸發(fā)input 事件 -
事件: cut民晒、copy、paste
這些事件發(fā)生于剪切/拷貝/粘貼一個值的時候
它們屬于 ClipboardEvent類锄禽, 并提供了對剪切/拷貝/粘貼的數據的訪問方法
<input type="text" id="input">
<script>
input.onpaste = function(event) {
alert("paste: " + event.clipboardData.getData('text/plain'));
event.preventDefault();
};
input.oncut = input.oncopy = function(event) {
alert(event.type + '-' + document.getSelection());
event.preventDefault();
};
</script>