HTML DOM 事件
HTML DOM 事件允許Javascript在HTML文檔元素中注冊不同事件處理程序。
事件通常與函數結合使用,函數不會在事件發生前被執行! (如用戶點擊按鈕)。
提示: 在 W3C 2 級 DOM 事件中規范了事件模型。
HTML DOM 事件
DOM: 指明使用的 DOM 屬性級別。
鼠標事件
屬性 | 描述 | DOM |
---|---|---|
onclick | 當用戶點擊某個對象時調用的事件句柄。 | 2 |
oncontextmenu | 在用戶點擊鼠標右鍵打開上下文菜單時觸發 | |
ondblclick | 當用戶雙擊某個對象時調用的事件句柄。 | 2 |
onmousedown | 鼠標按鈕被按下。 | 2 |
onmouseenter | 當鼠標指針移動到元素上時觸發。 | 2 |
onmouseleave | 當鼠標指針移出元素時觸發 | 2 |
onmousemove | 鼠標被移動。 | 2 |
onmouseover | 鼠標移到某元素之上。 | 2 |
onmouseout | 鼠標從某元素移開。 | 2 |
onmouseup | 鼠標按鍵被松開。 | 2 |
鍵盤事件
屬性 | 描述 | DOM |
---|---|---|
onkeydown | 某個鍵盤按鍵被按下。 | 2 |
onkeypress | 某個鍵盤按鍵被按下并松開。 | 2 |
onkeyup | 某個鍵盤按鍵被松開。 | 2 |
框架/對象(Frame/Object)事件
屬性 | 描述 | DOM |
---|---|---|
onabort | 圖像的加載被中斷。 ( <object>) | 2 |
onbeforeunload | 該事件在即將離開頁面(刷新或關閉)時觸發 | 2 |
onerror | 在加載文檔或圖像時發生錯誤。 ( <object>, <body>和 <frameset>) | |
onhashchange | 該事件在當前 URL 的錨部分發生修改時觸發。 | |
onload | 一張頁面或一幅圖像完成加載。 | 2 |
onpageshow | 該事件在用戶訪問頁面時觸發 | |
onpagehide | 該事件在用戶離開當前網頁跳轉到另外一個頁面時觸發 | |
onresize | 窗口或框架被重新調整大小。 | 2 |
onscroll | 當文檔被滾動時發生的事件。 | 2 |
onunload | 用戶退出頁面。 ( <body> 和 <frameset>) | 2 |
表單事件
屬性 | 描述 | DOM |
---|---|---|
onblur | 元素失去焦點時觸發 | 2 |
onchange | 該事件在表單元素的內容改變時觸發( <input>, <keygen>, <select>, 和 <textarea>) | 2 |
onfocus | 元素獲取焦點時觸發 | 2 |
onfocusin | 元素即將獲取焦點時觸發 | 2 |
onfocusout | 元素即將失去焦點時觸發 | 2 |
oninput | 元素獲取用戶輸入時觸發 | 3 |
onreset | 表單重置時觸發 | 2 |
onsearch | 用戶向搜索域輸入文本時觸發 ( <input="search">) | |
onselect | 用戶選取文本時觸發 ( <input> 和 <textarea>) | 2 |
onsubmit | 表單提交時觸發 | 2 |
剪貼板事件
屬性 | 描述 | DOM |
---|---|---|
oncopy | 該事件在用戶拷貝元素內容時觸發 | |
oncut | 該事件在用戶剪切元素內容時觸發 | |
onpaste | 該事件在用戶粘貼元素內容時觸發 |
打印事件
屬性 | 描述 | DOM |
---|---|---|
onafterprint | 該事件在頁面已經開始打印,或者打印窗口已經關閉時觸發 | |
onbeforeprint | 該事件在頁面即將開始打印時觸發 |
拖動事件
事件 | 描述 | DOM |
---|---|---|
ondrag | 該事件在元素正在拖動時觸發 | |
ondragend | 該事件在用戶完成元素的拖動時觸發 | |
ondragenter | 該事件在拖動的元素進入放置目標時觸發 | |
ondragleave | 該事件在拖動元素離開放置目標時觸發 | |
ondragover | 該事件在拖動元素在放置目標上時觸發 | |
ondragstart | 該事件在用戶開始拖動元素時觸發 | |
ondrop | 該事件在拖動元素放置在目標區域時觸發 |
多媒體(Media)事件
事件 | 描述 | DOM |
---|---|---|
onabort | 事件在視頻/音頻(audio/video)終止加載時觸發。 | |
oncanplay | 事件在用戶可以開始播放視頻/音頻(audio/video)時觸發。 | |
oncanplaythrough | 事件在視頻/音頻(audio/video)可以正常播放且無需停頓和緩沖時觸發。 | |
ondurationchange | 事件在視頻/音頻(audio/video)的時長發生變化時觸發。 | |
onemptied | 當期播放列表為空時觸發 | |
onended | 事件在視頻/音頻(audio/video)播放結束時觸發。 | |
onerror | 事件在視頻/音頻(audio/video)數據加載期間發生錯誤時觸發。 | |
onloadeddata | 事件在瀏覽器加載視頻/音頻(audio/video)當前幀時觸發觸發。 | |
onloadedmetadata | 事件在指定視頻/音頻(audio/video)的元數據加載后觸發。 | |
onloadstart | 事件在瀏覽器開始尋找指定視頻/音頻(audio/video)觸發。 | |
onpause | 事件在視頻/音頻(audio/video)暫停時觸發。 | |
onplay | 事件在視頻/音頻(audio/video)開始播放時觸發。 | |
onplaying | 事件在視頻/音頻(audio/video)暫停或者在緩沖后準備重新開始播放時觸發。 | |
onprogress | 事件在瀏覽器下載指定的視頻/音頻(audio/video)時觸發。 | |
onratechange | 事件在視頻/音頻(audio/video)的播放速度發送改變時觸發。 | |
onseeked | 事件在用戶重新定位視頻/音頻(audio/video)的播放位置后觸發。 | |
onseeking | 事件在用戶開始重新定位視頻/音頻(audio/video)時觸發。 | |
onstalled | 事件在瀏覽器獲取媒體數據,但媒體數據不可用時觸發。 | |
onsuspend | 事件在瀏覽器讀取媒體數據中止時觸發。 | |
ontimeupdate | 事件在當前的播放位置發送改變時觸發。 | |
onvolumechange | 事件在音量發生改變時觸發。 | |
onwaiting | 事件在視頻由于要播放下一幀而需要緩沖時觸發。 |
動畫事件
事件 | 描述 | DOM |
---|---|---|
animationend | 該事件在 CSS 動畫結束播放時觸發 | |
animationiteration | 該事件在 CSS 動畫重復播放時觸發 | |
animationstart | 該事件在 CSS 動畫開始播放時觸發 |
過渡事件
事件 | 描述 | DOM |
---|---|---|
transitionend | 該事件在 CSS 完成過渡后觸發。 |
其他事件
事件 | 描述 | DOM |
---|---|---|
onmessage | 該事件通過或者從對象(WebSocket, Web Worker, Event Source 或者子 frame 或父窗口)接收到消息時觸發 | |
onmousewheel | 已廢棄。 使用 onwheel 事件替代 | |
ononline | 該事件在瀏覽器開始在線工作時觸發。 | |
onoffline | 該事件在瀏覽器開始離線工作時觸發。 | |
onpopstate | 該事件在窗口的瀏覽歷史(history 對象)發生改變時觸發。 | |
onshow | 該事件當 <menu> 元素在上下文菜單顯示時觸發 | |
onstorage | 該事件在 Web Storage(HTML 5 Web 存儲)更新時觸發 | |
ontoggle | 該事件在用戶打開或關閉 <details> 元素時觸發 | |
onwheel | 該事件在鼠標滾輪在元素上下滾動時觸發 |
事件對象
常量
靜態變量 | 描述 | DOM |
---|---|---|
CAPTURING-PHASE | 當前事件階段為捕獲階段(3) | 1 |
AT-TARGET | 當前事件是目標階段,在評估目標事件(1) | 2 |
BUBBLING-PHASE | 當前的事件為冒泡階段 (2) | 3 |
屬性
屬性 | 描述 | DOM |
---|---|---|
bubbles | 返回布爾值,指示事件是否是起泡事件類型。 | 2 |
cancelable | 返回布爾值,指示事件是否可擁可取消的默認動作。 | 2 |
currentTarget | 返回其事件監聽器觸發該事件的元素。 | 2 |
eventPhase | 返回事件傳播的當前階段。 | 2 |
target | 返回觸發此事件的元素(事件的目標節點)。 | 2 |
timeStamp | 返回事件生成的日期和時間。 | 2 |
type | 返回當前 Event 對象表示的事件的名稱。 | 2 |
方法
方法 | 描述 | DOM |
---|---|---|
initEvent() | 初始化新創建的 Event 對象的屬性。 | 2 |
preventDefault() | 通知瀏覽器不要執行與事件關聯的默認動作。 | 2 |
stopPropagation() | 不再派發事件。 | 2 |
目標事件對象
方法
方法 | 描述 | DOM |
---|---|---|
addEventListener() | 允許在目標事件中注冊監聽事件(IE8 = attachEvent()) | 2 |
dispatchEvent() | 允許發送事件到監聽器上 (IE8 = fireEvent()) | 2 |
removeEventListener() | 運行一次注冊在事件目標上的監聽事件(IE8 = detachEvent()) | 2 |
事件監聽對象
方法
方法 | 描述 | DOM |
---|---|---|
handleEvent() | 把任意對象注冊為事件處理程序 | 2 |
文檔事件對象
方法
方法 | 描述 | DOM |
---|---|---|
createEvent() | 2 |
鼠標/鍵盤事件對象
屬性
屬性 | 描述 | DOM |
---|---|---|
altKey | 返回當事件被觸發時,"ALT" 是否被按下。 | 2 |
button | 返回當事件被觸發時,哪個鼠標按鈕被點擊。 | 2 |
clientX | 返回當事件被觸發時,鼠標指針的水平坐標。 | 2 |
clientY | 返回當事件被觸發時,鼠標指針的垂直坐標。 | 2 |
ctrlKey | 返回當事件被觸發時,"CTRL" 鍵是否被按下。 | 2 |
Location | 返回按鍵在設備上的位置 | 3 |
charCode | 返回onkeypress事件觸發鍵值的字母代碼。 | 2 |
key | 在按下按鍵時返回按鍵的標識符。 | 3 |
keyCode | 返回onkeypress事件觸發的鍵的值的字符代碼,或者 onkeydown 或 onkeyup 事件的鍵的代碼。 | 2 |
which | 返回onkeypress事件觸發的鍵的值的字符代碼,或者 onkeydown 或 onkeyup 事件的鍵的代碼。 | 2 |
metaKey | 返回當事件被觸發時,"meta" 鍵是否被按下。 | 2 |
relatedTarget | 返回與事件的目標節點相關的節點。 | 2 |
screenX | 返回當某個事件被觸發時,鼠標指針的水平坐標。 | 2 |
screenY | 返回當某個事件被觸發時,鼠標指針的垂直坐標。 | 2 |
shiftKey | 返回當事件被觸發時,"SHIFT" 鍵是否被按下。 | 2 |
方法
方法 | 描述 | W3C |
---|---|---|
initMouseEvent() | 初始化鼠標事件對象的值 | 2 |
initKeyboardEvent() | 初始化鍵盤事件對象的值 | 3 |
如您還有不明白的可以在下面與我留言或是與我探討QQ群308855039,我們一起飛!
nmouseenter與onmouseover事件作用:
當鼠標進入(經過)觸發事件。
但他們之間有一點小的差別。我們來看這個例子。
我們創建這樣的HTML頁面結構
然后,給定適當的css樣式如下:
這樣就達到了平常網站菜單的效果
分別給ul和li添加mouseover事件。
我們給ul與li都加上mouseover事件,那么當鼠標經過li時,會有事件冒泡,會觸發ul上面的mouseover事件。一次彈出兩個alert窗口。
使用mouseenter事件則不會出現事件冒泡
應用于下拉菜單特效等
有不懂的歡迎私信我喲~
內容是《Web前端開發之Javascript視頻》的課件,請配合大師哥《Javascript》視頻課程學習。
MouseEvent鼠標事件:
DOM2級事件中定義了7個,DOM3級事件增加了2個鼠標事件:
鼠標事件中還有一類滾輪事件,只包括一個mousewheel事件,但此事件已歸WheelEvent類了;
document.addEventListener("click", function(event){
console.log(event); // MouseEvent
},false);
document.addEventListener("mousewheel", function(event){
console.log(event); // WheelEvent
},false);
可以檢測瀏覽器是否支持所有事件,如:
var isSupported = document.implementation.hasFeature("MouseEvent", "3.0");
頁面上的所有元素都支持鼠標事件;除了mouseenter和mouseleave,其他所有鼠標事件都會冒泡,也可以取消,而取消鼠標事件將會影響瀏覽器的默認行為,也會影響其他事件;
click事件:
在一個元素上被按下和放開時,click事件就會被觸發,包括鼠標單擊(通常是左按鈕)或鍵盤回車,或者在腳本中為一個對象執行了click()方法也會觸發該事件;
var btn = document.getElementById("btn");
btn.click();
在一個focusable元素上單擊時,該元素就獲得了焦點,就會觸發focus事件和click事件;
function handler(event){
console.log(event.type);
}
var txt = document.getElementById("txt");
txt.addEventListener("click", handler,false);
txt.addEventListener("focus", handler,false);
其觸發的順序為:focus、click;
只有在同一個元素上相繼觸發mousedown和mouseup事件,才會觸發click事件;如果mousedown或mouseup中一個被取消,就不會觸發click事件,類似只有觸發兩次click事件才會觸發一次dbclick事件;
這4個鼠標事件觸發順序:
mousedown –> mouseup –> click –> mousedown –> mouseup –> click –> dbclick;
mouseover和mouseout事件:
當鼠標進入或移出元素時觸發這兩個事件;
示例:鼠標懸停改變表格行的背景色,如:
<style>
#mytable{width: 400px; border-collapse: collapse;}
#mytable td{ height: 20px; border: 1px solid #000;}
</style>
<table id="mytable">
<tr>
<td></td> <td></td> <td></td>
</tr>
<!-- 多行 -->
</table>
<script>
// 表格名稱、奇數行背景、偶數行背景、鼠標經過背景、點擊后背景
function changeBg(table, oddColor, evenColor,overColor, clickColor){
var rows = document.getElementById(table).rows;
for(var i=0; i < rows.length; i++){
var tr = rows[i];
tr.style.backgroundColor = (tr.sectionRowIndex % 2 == 0) ? oddColor : evenColor;
tr.original = true;
tr.addEventListener("click", function(event){
if(this.original){
this.original = false;
this.style.backgroundColor = clickColor;
}else{
this.original = true;
this.style.backgroundColor = (this.sectionRowIndex % 2 == 0) ? oddColor : evenColor;
}
});
tr.addEventListener("mouseover", function(){
if(this.original)
this.style.backgroundColor = overColor;
});
tr.addEventListener("mouseout", function(){
if(this.original)
this.style.backgroundColor = (this.sectionRowIndex % 2 == 0) ? oddColor : evenColor;
});
}
}
changeBg("mytable", "#FFF", "#ccc", "#cfc", "#f00");
</script>
mouseover和mouseout事件會冒泡,因此,當觸發mouseout事件時,有可能鼠標真的離開了目標元素,但也有可能是從這個元素移動到它的子元素上,或者從一個子元素移動到另一個子元素,所以在這種情況下,需要判斷鼠標的確切位置;
<div id="mydiv">
<div id="div1">div1</div>
<div id="div2">div2</div>
</div>
<script>
var oDiv = document.getElementById("mydiv");
oDiv.addEventListener("mouseover", function(event){
console.log("mouseover:" + event.target.id);
},false);
oDiv.addEventListener("mouseout", function(event){
console.log("mouseout:" + event.target.id);
},false);
</script>
DOM3提供了兩個不冒泡的對應版本mouseenter和mouseleave,如:
oDiv.addEventListener("mouseenter", function(event){
console.log("mouseenter:" + event.target.id);
},false);
oDiv.addEventListener("mouseleave", function(event){
console.log("mouseleave:" + event.target.id);
},false);
示例:圖片遮罩,如:
<style>
*{margin:0; padding: 0;}
ul,li{list-style: none;}
ul{display:flex; flex-wrap: wrap;}
li{width: 200px;}
li>a{display: block; width: 100%; position: relative;}
li img{width:200px;}
</style>
<ul id="mylist">
<li><a href="#" title="天下第一山"><img src="images/1.jpg"></a></li>
<li><a href="#" title="zeronetwork"><img src="images/2.jpg"></a></li>
<li><a href="#" title="Javascript"><img src="images/3.jpg"></a></li>
<li><a href="#" title="Web前端開發"><img src="images/4.jpg"></a></li>
</ul>
<script>
window.onload = function(){
var mylist = document.getElementById("mylist");
var aList = mylist.getElementsByTagName("a");
for(var i=0,len=aList.length; i<len; i++){
var a = aList[i];
var mask = null;
a.addEventListener("mouseenter", function(event){
mask = this.getElementsByClassName("mask")[0];
if(!mask){
mask = document.createElement("div");
mask.className = "mask";
}
mask.style.backgroundColor = "rgba(0,0,0,0.8)";
var computedStyle = document.defaultView.getComputedStyle(this, null);
mask.style.width = computedStyle.width;
mask.style.height = computedStyle.height;
mask.style.position = "absolute";
mask.style.color = "#FFF";
mask.style.textAlign = "center";
mask.style.lineHeight = computedStyle.height;
mask.innerHTML = this.title;
this.insertBefore(mask, this.firstChild);
},false);
a.addEventListener("mouseleave", function(event){
var mask = this.getElementsByClassName("mask")[0];
console.log(this);
if(mask){
this.removeChild(mask);
}
},false);
}
}
</script>
mouseleave和mouseenter事件的行為與CSS的:hover 偽類非常相似;
mousemove事件,會頻繁觸發,所以,在其事件處理程序中不能放置計算密集的任務,或者使用事件節流的方式;
鼠標事件對象:
鼠標事件屬于MouseEvent類,該類指的是用戶與指針設備( 如鼠標 )交互時發生的事件,其繼承自UIEvent類;
MouseEvent類定義了一組專屬于鼠標事件的屬性,描述了當事件發生時鼠標的位置和按鍵的狀態,也包含了是否有輔助鍵被按下等所有信息;
客戶區坐標位置:
clientX與clientY屬性:取得鼠標相對于瀏覽器視口的坐標位置;
var oDiv = document.getElementById("mydiv");
EventUtil.addHandler(oDiv, "click", function(event){
event = EventUtil.getEvent(event);
console.log(event);
console.log(event.clientX + "," + event.clientY);
});
注,這個位置不包括頁面滾動的距離,如果加上窗口的滾動偏移量,就會把鼠標位置轉換成文檔坐標;
所有瀏覽器也都實現了x和y屬性,其是clientX和clientY的別名;
示例:計算鼠標拖動的直線距離,如:
var obj = {};
function downHandler(event){
obj.x = event.x;
obj.y = event.y;
}
function upHandler(event){
obj.mx = event.x - obj.x;
obj.my = event.y - obj.y;
obj.d = Math.sqrt((Math.pow(obj.mx,2) + Math.pow(obj.my,2)));
console.log(obj.mx, obj.my, obj.d);
}
document.addEventListener("mousedown", downHandler, false);
document.addEventListener("mouseup", upHandler, false);
示例:自定義鼠標樣式,如:
document.documentElement.style.cursor = "none";
var cursor = document.createElement("span");
cursor.style.width = "20px";
cursor.style.height = "20px";
cursor.style.position = "absolute";
cursor.style.backgroundColor = "#000";
document.body.appendChild(cursor);
document.addEventListener("mousemove", function(event){
cursor.style.left = event.clientX - cursor.offsetWidth / 2 + "px";
cursor.style.top = event.clientY - cursor.offsetHeight / 2 + "px";
},false);
文檔坐標位置:
pageX和pageY屬性:取得鼠標光標在文檔中的位置;
console.log(event.pageX + "," + event.pageY);
這個位置是包括滾動距離的,在文檔沒有滾動的情況下,pageX、pageY與clientX、clientY值相等;
IE8及以下不支持文檔坐標,不過使用客戶區坐標和滾動信息可以計算出來,也就是需要用到scrollLeft和scrollTop屬性,如:
var oDiv = document.getElementById("mydiv");
EventUtil.addHandler(oDiv, "click", function(event){
event = EventUtil.getEvent(event);
var pageX = event.pageX,
pageY = event.pageY;
if(pageX == undefined)
pageX = event.clientX + (document.body.scrollLeft || document.documentElement.scrollLeft);
if(pageY == undefined)
pageY = event.clientY + (document.body.scrollTop || document.documentElement.scrollTop);
console.log(pageX + ":" + pageY);
});
屏幕坐標位置:screenX與screenY屬性:取得相對于屏幕的位置;
console.log(event.screenX + ":" + event.screenY);
元素坐標位置:
offsetX和offsetY屬性,返回與目標元素(target)的內填充邊(padding edge)在X和Y軸方向上的偏移量;坐標原點為padding區左上角,因此,如果目標元素有邊框,鼠標的位置位于邊框上,該屬性值為負值;
var oDiv = document.getElementById("mydiv");
oDiv.style.position = "relative";
oDiv.style.left = "100px";
oDiv.style.top = "50px";
document.addEventListener("click", function(event){
console.log("offsetX:" + event.offsetX + ",offsetY:" + event.offsetY);
},false);
如果元素滾動了,也包括offsetLeft和offsetTop值;
示例:繪圖:
<style>
canvas{border: 1px solid;}
</style>
<canvas id="mydraw" width="560" height="360"></canvas>
<script>
var isDrawing = false;
var x=0, y=0;
var mydraw = document.getElementById("mydraw");
var context = mydraw.getContext("2d");
mydraw.addEventListener("mousedown", function(event){
x = event.offsetX, y = event.offsetY;
isDrawing = true;
});
mydraw.addEventListener("mousemove", function(event){
if(isDrawing === true){
drawLine(context, x, y, event.offsetX, event.offsetY);
x = event.offsetX, y = event.offsetY;
}
});
window.addEventListener("mouseup", function(event){
if(isDrawing === true){
drawLine(context, x, y, event.offsetX, event.offsetY);
x = 0, y = 0;
isDrawing = false;
}
});
function drawLine(content, x1, y1, x2, y2){
context.beginPath();
context.strokeStyle = "black";
context.lineWidth = 1;
context.moveTo(x1, y1);
context.lineTo(x2, y2);
context.stroke();
context.closePath();
}
</script>
movementX和movementY屬性:
返回當前事件和上一個mousemove事件之間鼠標在水平或垂直方向上的移動值;
即:currentEvent.movementX = currentEvent.screenX - previousEvent.screenX;
currentEvent.movementY = currentEvent.screenY - previousEvent.screenY;
document.addEventListener("mousemove", function(event){
console.log(event.movementX);
},false);
但IE不支持,并且此屬性只有在mousemove事件中才能返回正確的值;
輔助鍵:
DOM規定了4個屬性:shiftkey、ctrlKey、altkey和metaKey,表示當事件發生時shift、ctrl、alt和meta4個鍵的按下狀態,均為布爾值,如果按下為true,反之為false;
var btn = document.getElementById("btn");
EventUtil.addHandler(btn, "click", handler);
function handler(event){
event = EventUtil.getEvent(event);
var keys = new Array();
if(event.shiftKey)
keys.push("shift");
if(event.altKey)
keys.push("alt");
if(event.ctrlKey)
keys.push("ctrl");
if(event.metaKey)
keys.push("meta");
console.log("keys:" + keys.join(","));
}
標準瀏覽器支持,但IE不支持metaKey屬性;
getModifierState(key)方法:返回指定修飾鍵的當前狀態;
參數key可以為Control、Alt、Shift和Meta,注意,大小寫是敏感的;
btn.addEventListener("click", function(event){
console.log(event.getModifierState("Control"));
},false);
relatedTarget相關元素:
在發生mouseover和mouseout事件時,會涉及到多個元素;對mouseover而言,事件的主目標是獲得光標的元素,而相關元素就是那個失去光標的元素(這個相關元素也可以把它叫做次目標元素);對mouseout事件而言,事件的主目標是失去光標的元素,而相關元素則是獲得光標的元素;
DOM通過event對象的relatedTarget屬性提供了相關元素的信息,該屬性只針于mouseover、mouseout、mouseenter、mouseleave、focusin、focusout、dragenter(拖動元素進入)事件時才有值;對于其他事件,該屬性為null;
var oDiv = document.getElementById("mydiv");
oDiv.addEventListener("mouseover", function(event){
console.log(event);
},false);
oDiv.addEventListener("mouseout", function(event){
console.log(event);
},false);
IE8及以下不支持relatedTarget屬性,但提供了保存著同樣信息不同的屬性,在mouseover事件觸發時,fromElement屬性中保存了相關元素,toElement屬性為事件目標;在mouseout事件觸發時,toElement屬性保存了相關元素,fromElement屬性為事件目標;
document.addEventListener("mouseover", function(event){
console.log(event.fromElement);
console.log(event.toElement);
},false);
跨瀏覽器取得相關元素,添加到eventutil文件中;
getRelatedTarget: function(event){
if(event.relatedTaret)
return event.relatedTaret;
else if(event.toElement)
return event.toElement;
else if(event.fromElement)
return event.fromElement;
else
return null;
}
應用:
var oDiv = document.getElementById("mydiv");
EventUtil.addHandler(oDiv, "mouseout", function(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
var relatedTarget = EventUtil.getRelatedTarget(event);
console.log(relatedTarget);
console.log(relatedTarget.tagName);
})
鼠標按鈕:
對于mousedown和mouseup事件來說,在其event對象存在一個button屬性,表示按下或釋放的哪個鼠標按鈕;可能有3個值:0主按鈕;1中間按鈕鼠標滾輪);2次按鈕;
btn.addEventListener("mouseup", function(event){
console.log(event.button);
},false);
IE8及以下也提供了button,但其值與DOM的button屬性有很大差異:0 沒有按下按鈕;1按下主按鈕;2次按鈕;3同時按下主次按鈕;4中間按鈕;5同時按下主和中間按鈕;6次和中間按鈕;7同時按下三個;
跨瀏覽器取得button屬性,在eventutil文件中添加:
getButton: function(event){
if(document.implementation.hasFeature("MouseEvents","2.0"))
return event.button;
else{
switch(event.button){
case 0:
case 1:
case 3:
case 5:
case 7:
return 0;
case 2:
case 6:
return 2;
case 4:
return 1;
}
}
}
buttons屬性:
當鼠標事件觸發的時,如果多個鼠標按鈕被按下,將會返回一個或者多個代表鼠標按鈕的位掩碼:
buttons的值為各鍵對應值做按位與(+)計算后的值,例如,如果右鍵(2)和滾輪鍵(4)被同時按下,buttons的值為 2 + 4 = 6,如:
btn.addEventListener("mousedown", function(event){
console.log(event.button);
console.log(event.buttons);
},false);
屬性button和buttons 是不同的,buttons可指示任意鼠標事件中鼠標的按鍵情況,而 button只能保證在由按下和釋放一個或多個按鍵時觸發的事件中獲得正確的值;
which屬性:
當鼠標事件觸發時,表示被按下的按鈕,其返回特定按鍵的數字,0為無、1為左鍵、2為中間滾輪、3為右鍵;其是非標準屬性,但所有瀏覽器都支持;
btn.addEventListener("mousedown", function(event){
console.log(event.which);
console.log(event.button);
},false);
注意,此時應該注冊mousedown或mouseup事件而不是click事件,因為右擊或按下中間滾動不會觸發click事件;
detail屬性:
DOM2在event對象中提供了detail屬性,用于給出有關事件的更多信息;對于鼠標click、mousedown和mouseup事件來說,detail中包含了一個數值,表示目標元素被單擊了多少次,其它事件返回0;detail從1開始計數,每次單擊都會遞增;
console.log(event.detail);
用此屬性就可以判斷用戶是單擊、雙擊還是三擊;如果鼠標在mousedown和mouseup之間移動了位置,則detail被重置為0;
IE也通過下列屬性為鼠標事件提供了更多信息:
這些屬性只有IE支持;
示例:拖動文檔元素,當鼠標按下或釋放時,會觸發mousedown和mouseup事件,因此,通過這兩個事件,可以探測和響應鼠標的拖動;如:
function drag(elementToDrag, event){
var scroll = {x:0, y:0};
var startX = event.clientX + scroll.x;
var startY = event.clientY + scroll.y;
var origX = elementToDrag.offsetLeft;
var origY = elementToDrag.offsetTop;
var deltaX = startX - origX;
var deltaY = startY - origY;
if(document.addEventListener){
document.addEventListener("mousemove", moveHandler, true);
document.addEventListener("mouseup", upHandler, true);
}else if(document.attachEvent){
elementToDrag.setCapture();
elementToDrag.attachEvent("onmousemove", moveHandler);
elementToDrag.attachEvent("onmouseup", upHandler);
// 作為mouseup事件看待鼠標捕獲的丟失
elementToDrag.attachEvent("onlosecapture", upHandler);
}
// 處理了這個事件,不讓任何其他元素看到它
if(event.stopPropagation)
event.stopPropagation();
else
event.cancelBubble = true;
// 現在阻止任何默認操作
if(event.preventDefault)
event.preventDefault();
else
event.returnValue = false;
// 當元素正在被拖動時,這就是捕獲mousemove事件的處理程序
// 它用于移動這個元素
function moveHandler(e){
if(!e) e = window.event;
// 移動這個元素到當前鼠標位置
// 通過滾動條的位置和初始單擊的偏移量來調整
// var scroll = getScrollOffsets();
var scroll = {x:0,y:0};
elementToDrag.style.left = (e.clientX + scroll.x - deltaX) + "px";
elementToDrag.style.top = (e.clientY + scroll.y - deltaY) + "px";
// 同時不讓任何其他元素看到這個事件
if(e.stopPropagation)
e.stopPropagation();
else
e.cancelBubble = true;
}
// 這是捕獲在拖動結束時發生的最終mouseup事件的處理程序
function upHandler(e){
if(!e) e = window.event;
// 注銷捕獲事件處理程序
if(document.removeEventListener){
document.removeEventListener("mouseup", upHandler, true);
document.removeEventListener("mousemove", moveHandler, true);
}else if(document.detachEvent){
elementToDrag.detachEvent("onlosecapture", upHandler);
elementToDrag.detachEvent("onmouseup", upHandler);
elementToDrag.detachEvent("onmousemove", moveHandler);
elementToDrag.releaseCapture();
}
// 并且不讓事件進一步傳播
if(e.stopPropagation)
e.stopPropagation();
else
e.cancelBubble = true;
}
}
應用:
<div style="position: absolute;left:100px;top:100px; width:150px;background-color: purple;">
<div style="background-color: gray;" onmousedown="drag(this.parentNode, event);">標題欄-拖動我</div>
<p>Lorem ...</p>
</div>
CSS的pointer-events屬性:
指定在什么情況下 (如果有) 某個特定的元素可以成為鼠標事件的target;主要用于 SVG元素;
可能的值為:
該屬性可以:
<style>
/* 鏈接不會跳轉 */
a[href="https://www.zeronetwork.cn/"]{
pointer-events: none;
}
</style>
<a href="https://www.zeronetwork.cn/">零點網絡</a>
<script>
var link = document.querySelector("a");
function handler(event){
console.log(event);
}
// 以下均無效
link.addEventListener("click",handler,false);
link.addEventListener("mouseover",handler,false);
link.addEventListener("drag",handler,false);
</script>
此屬性可以通過控制臺改變,如在控制臺輸入:document.querySelector("a").style.pointerEvents = "auto";此時,超鏈接就可以觸發了;
<style>
/* 使所有img對任何鼠標事件(如拖動、懸停、單擊等)無反應 */
img{
pointer-events: none;
}
</style>
<img src="images/1.jpg" />
<script>
var img = document.querySelector("img");
function handler(event){
console.log(event);
}
// 以下均無效
img.addEventListener("click",handler,false);
img.addEventListener("mouseover",handler,false);
img.addEventListener("drag",handler,false);
</script>
除了指示該元素不是鼠標事件的目標之外,值none表示鼠標事件“穿透”該元素并且指定該元素“下面”的任何元素;如:
<style>
.container{position: relative; width: 200px; height: 150px;}
.mask{width: 100%; height: 100%; background-color: rgba(0, 0, 0, .5);
position: absolute; pointer-events: none; color:#FFF}
.container img{width: 100%; height: 100%;}
</style>
<div class="container">
<div class="mask"></div>
<a href="https://www.zeronetwork.cn"><img src="images/1.jpg" /></a>
</div>
<script>
var link = document.querySelector(".container>a");
link.addEventListener("mouseover", function(event){
var mask = event.currentTarget.parentNode.querySelector(".mask");
mask.innerHTML = event.currentTarget.title;
},false);
link.addEventListener("mouseout", function(event){
var mask = event.currentTarget.parentNode.querySelector(".mask");
mask.innerHTML = "";
},false);
</script>
示例:取得一個元素的相對鼠標坐標,如:
<style>
.parent{ width:400px; height:400px; padding: 50px; margin:100px; background:#f20; }
.child{ width:200px; height:200px; padding:50px; background:#ff0;}
.child-child{ width:50px; height:50px; background:#00d;}
</style>
<div class="parent" id="parent">
<div class="child">
<div class="child-child"></div>
</div>
</div>
<script>
var parent = document.getElementById("parent");
parent.addEventListener("click",function(event){
console.info(event.offsetX);
});
</script>
使用pointer-events屬性后再獲取,如為child和child-child類分別添加pointer-events屬性,此時打印的值就是相對于parent元素的坐標了;
使用pointer-events來阻止元素成為鼠標事件目標不一定意味著元素上的事件偵聽器永遠不會觸發,如果元素后代明確指定了pointer-events屬性并允許其成為鼠標事件的目標,那么指向該元素的任何事件在事件傳播過CSS添加pointer-events:none,再為其子元素添加pointer-events:all,此時在子元素上單擊就可以觸發注冊在父元素上的事件處理程序;
當然,位于父元素但不在后代元素上的鼠標活動都不會被父元素和后代元素捕獲(鼠標活動將會穿過父元素而指向位于其下面的元素);
var subchild = document.querySelector(".child-child");
subchild.addEventListener("click",function(event){
console.log("child-child");
parent.style.pointerEvents = "auto";
});
該屬性也可用來提高滾動時的幀頻;例如,當頁面滾動時,如果恰巧鼠標懸停在某些元素上,則會觸發其上的hover效果或觸發onmouseover事件,有可能會造成滾動出現問題,此時,如果對body元素應用pointer-events:none,則會禁用了包括hover在內的鼠標事件,從而提高滾動性能;
<style>
#mydiv:hover{
background-color: lightgreen !important;
}
</style>
<div id="mydiv" style="height: 300px;background-color: purple;"></div>
<div style="height: 1000px;"></div>
<script>
var mydiv = document.getElementById("mydiv");
mydiv.addEventListener("mouseover", function(event){
console.log(event);
},false);
</script>
滾動頁面時觸發了mouseover事件及hover效果,可以在scroll事件中進行相應的處理,如:
var timeoutId = null;
window.addEventListener("scroll", function(event){
document.body.style.pointerEvents = "none";
if(timeoutId){
clearTimeout(timeoutId);
timeoutId = null;
}else{
timeoutId = setTimeout(function(){
console.log("解禁了");
document.body.style.pointerEvents = "auto";
},500);
}
},false);
部分瀏覽器不支持該屬性,可以判斷其支持情況,如:
var supportsPointerEvents = (function(){
var dummy = document.createElement("_");
if(!('pointerEvents' in dummy.style))
return false;
dummy.style.pointerEvents = 'auto';
// 如果是真的屬性,則賦值不成功
dummy.style.pointerEvents = 'x';
document.body.appendChild(dummy);
var result = getComputedStyle(dummy).pointerEvents === 'auto';
document.body.removeChild(dummy);
return result;
})();
console.log(supportsPointerEvents);
WheelEvent滾輪事件:
當用戶通過鼠標滾輪與頁面交互,在垂直方向上滾動頁面時(無論向上還是向下),就會觸發mousewheel事件;該事件可以在任何元素上觸發,最終會冒泡到document或window對象,也可以阻止其默認行為;
document.addEventListener("mousewheel", function(event){
console.log(event); // WheelEvent
},false);
WheelEvent類:
表示用戶滾動鼠標滾輪或類似輸入設備時觸發的事件,用以替代MouseWheelEvent和MouseScrollEvent,mousewheel實際上是屬于MouseWheelEvent類,而后面要講的Firefox中的DOMMouseScroll屬于MouseScrollEvent類,它們兩者都不屬于標準,兼容性也不好,為了統一兩者,就出現了標準的WheelEvent類;
WheelEvent類繼承自MouseEvent類(MouseEvent類繼承自UIEvent類),所有也可以把它看作是鼠標事件,因此,對于WheelEvent事件對象來說,其中也保存著大量與MouseEvent事件同樣的屬性,例如,四對有關獲取坐標的屬性、which(值為0)、relatedTarget(為null)等等;還包括輔助鍵的屬性;
mousewheel事件中的event對象,除了保存鼠標事件的所有標準信息外,還包含一個特殊的wheelDelta屬性,其指定用戶滾動滾輪有多遠,當用戶向前滾動鼠標滾輪時,該屬性值是120的倍數,當向后滾動時,該值是-120的倍數;
EventUtil.addHandler(document, "mousewheel", function(event){
event = EventUtil.getEvent(event);
console.log(event);
console.log(event.wheelDelta);
})
如果要判斷用戶滾動的方向,只要檢測wheelDelta屬性的正負號即可;在Opera9.5之前的版本中,wheelDelta的值的正負號是顛倒的;
除了wheelDelta屬性外,事件對象還有wheelDeltaX和wheelDeltaY屬性,并且wheelDelta和wheelDeltaY的值一直相同;
console.log(event.wheelDelta);
console.log(event.wheelDeltaY);
console.log(event.wheelDeltaX);
IE不支持這兩個屬性;
Firefox不支持mousewheel事件,但支持一個名為DOMMouseScroll的類似事件,也是在鼠標滾輪滾動時觸發,它也被視為鼠標事件,也包含與鼠標事件有關的所有鼠標;而有關鼠標滾輪的信息則保存在detail屬性中,該屬性與wheelDelta作用相同;當向前滾動鼠標滾輪時,該屬性返回-3的位數,反之返回3的位數;
可以把該事件添加到頁面中的任何元素,而且該事件會冒泡到window對象;
EventUtil.addHandler(document, "DOMMouseScroll", function(event){
event = EventUtil.getEvent(event);
console.log(event);
console.log(event.detail); // 向前為-3,向后是3
})
detail屬性值與wheelDelta的值的關系是:wheelDelta等于detail乘以-40;
可以跨瀏覽器取得鼠標滾輪增值(delta),并添加到eventutil.js中,如:
getWheelDelta: function(event){
if(event.wheelDelta){
return event.wheelDelta;
}else
return -event.detail * 40;
}
應用時,需要同時注冊mousewheel和DOMMouseScroll事件,如:
function handlerMouseWheel(event){
event = EventUtil.getEvent(event);
var delta = EventUtil.getWheelDelta(event);
console.log(delta);
}
EventUtil.addHandler(document, "mousewheel", handlerMouseWheel);
EventUtil.addHandler(document, "DOMMouseScroll", handlerMouseWheel);
另外,DOMMouseEvent事件對象中還有一個axis屬性,其返回一個long型常量值,表明鼠標滾輪滾動的方向,當返回常量HORIZONTAL_AXIS,值為1時,表示由鼠標滾輪的橫向滾動觸發的,當返回VERTICAL_AXIS,值為2時,表示是由鼠標滾輪的縱向滾動觸發的;
wheel事件:
DOM3事件定義了一個名為wheel事件,用于替代mousewheel和DOMMouseScroll事件;事件對象中保存著deltaX、deltaY及deltaZ屬性:用來獲取三個不同的鼠標滾軸;大多數鼠標滾輪是一維或二維的,所以并不能使用deltaZ屬性;
EventUtil.addHandler(document, "wheel", function(event){
event = EventUtil.getEvent(event);
console.log(event); // WheelEvent
console.log(event.wheelDelta); // -120
console.log(event.wheelDeltaY); // -120
console.log(event.deltaX); // -0
console.log(event.deltaY); // chrome返回100,Firefox返回63
console.log(event.deltaZ); // 0
});
這些值必須乘以-1.2,才和mousewheel事件的wheelDelta值和正負號相匹配;
wheel事件對象還有一個deltaMode屬性,只讀,其返回long常量值,表示各delta*的值的單位,其值及所表示的單位如下:
常量值描述
console.log(event.deltaMode);
示例:在Enclose.js文件中定義enclose()函數,可以把一個圖片裝載到一個容器中,并且能移動這個容器,也能改變容器的大小,如:
function enclose(content, framewidth, frameheight, contentX, contentY){
// 這些參數不僅僅是初始值,它們保存當前狀態,能被mousewheel處理程序使用和修改
framewidth = Math.max(framewidth, 50);
frameheight = Math.max(frameheight, 50);
contentX = Math.min(contentX, 0) || 0;
contentY = Math.min(contentY, 0) || 0;
// 創建frame元素,且設置CSS類和樣式
var frame = document.createElement("div");
frame.className = "enclose";
frame.style.width = framewidth + "px";
frame.style.height = frameheight + "px";
frame.style.overflow = "hidden"; // 沒有滾動條,不能溢出
frame.style.boxSizing = "border-box"; // 能簡化調整frame大小的計算
content.parentNode.insertBefore(frame, content);
frame.appendChild(content);
// 確定元素相對于frame的位置
content.style.position = "relative";
content.style.left = contentX + "px";
content.style.top = contentY + "px";
var isFirefox = (navigator.userAgent.indexOf('Gecko') != -1);
// 注冊mousewheel事件處理程序
frame.onwheel = wheelHandler;
frame.onmousewheel = wheelHandler;
if(isFirefox)
frame.addEventListener("DOMMouseScroll", wheelHandler, false);
function wheelHandler(event){
var e = event || window.event;
var deltaX = e.deltaX / 3.33 || // wheel事件
e.wheelDeltaX / 4 || // mousewheel事件
0 // 屬性未定義
var deltaY = e.deltaY / 3.33 ||
e.wheelDeltaY / 4 ||
(e.wheelDeltaY === undefined && // 如果沒有2D屬性
e.wheelDelta / 4) || // 就使用1D的滾輪屬性
e.detail * -1.2 || // DOMMouseScroll事件
0; // 屬性未定義
if(isFirefox && e.type !== "DOMMouseScroll")
frame.removeEventListener("DOMMouseScroll", wheelHandler, false);
// 獲取內容元素的當前尺寸
var contentbox = content.getBoundingClientRect();
var contentwidth = contentbox.right - contentbox.left;
var contentheight = contentbox.bottom - contentbox.top;
// 如果按下Alt鍵,就可以調整frame大小
if(e.altKey){
if(deltaX){
framewidth -= deltaX; // 新寬度,但不能比內容大
framewidth = Math.min(framewidth, contentwidth);
framewidth = Math.max(framewidth, 50); // 不能小于50
frame.style.width = framewidth + "px";
}
if(deltaY){
frameheight -= deltaY;
frameheight = Math.min(frameheight, contentheight);
frameheight = Math.max(frameheight - deltaY, 50);
frame.style.height = frameheight + "px";
}
}else{ // 沒有按Alt鍵,就可以平移frame中的內容
if(deltaX){
var minoffset = Math.min(framewidth - contentwidth, 0);
// 把deltaX添加到contentX中,但不能小于minoffset
contentX = Math.max(contentX + deltaX, minoffset);
contentX = Math.min(contentX, 0);
content.style.left = contentX + "px";
}
if(deltaY){
var minoffset = Math.min(frameheight - contentheight, 0);
contentY = Math.max(contentY + deltaY, minoffset);
contentY = Math.min(contentY, 0);
content.style.top = contentY + "px";
}
}
if(e.preventDefault)
e.preventDefault();
if(e.stopPropagation)
e.stopPropagation();
e.cancelBubble = true;
e.returnValue = false;
return false;
}
}
應用:
<style>
div.enclose{border: 10px solid; margin:10px}
</style>
<img id="content" src="images/1.jpg" />
<script>
window.onload = function(){
enclose(document.getElementById("content"),400,200,-200,-300);
}
</script>
不要混淆wheel事件和scroll事件:wheel事件的默認動作取決于瀏覽器實現,因此wheel事件不一定會觸發scroll事件;即便滾輪事件引發了文檔內容的滾動行為,也不表示wheel事件中的delta*值恰好反映文檔內容的滾動方向;因此,不要依賴delta*屬性獲知文檔內容的滾動方向,可在文檔內容滾動事件中監視target的scrollLeft和scrollTop的變化以推斷滾動方向;
*請認真填寫需求信息,我們會在24小時內與您取得聯系。