JavaScript基礎入門09
目錄
- JavaScript 基礎入門09
- Event
- 自定義右鍵菜單
- 獲取鼠標按鍵
- 獲取鼠標坐標
- 獲取鍵盤按鍵
- 頁面中位置的獲取
- 瀏覽器的默認行為
- 冒泡
- 什麽是冒泡
- 小練習
JavaScript 基礎入門09
Event
Event 是一個事件對象,當一個事件發生後,和當前事件發生相關的詳細信息會被臨時存儲到一個指定的地方,也就是event對象,以方便我們在需要的時候調用。
在這一點上,非常類似於飛機當中的黑匣子,會記錄著飛機的詳細信息,當飛機失事的時候可以在黑匣子中找到相關的信息。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button id="btn">點擊</button> </body> <script> var btn = document.getElementById('btn'); btn.onclick = function () { console.log(event); // 查看event對象 MouseEvent?{isTrusted: true, screenX: 27, screenY: 160, clientX: 27, clientY: 25,?…} } </script> </html>
在上面的代碼中,我們在單擊事件的處理函數內打印了event對象,返回值的結果為MouseEvent
事件對象。
當我們在不同的事件中打印event對象,返回的結果會根據不同的事件類型返回不同的結果。
但是我們在使用的過程中需要考慮一下事件的兼容性,為了更好的兼容性,我們可以采用下面的寫法:
var env = env || window.event
// 或者
var env = env || event
我們還是以上面的例子為例,我們為了兼容性的處理,可以將代碼更改為如下的內容:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button id="btn">點擊</button> </body> <script> var btn = document.getElementById('btn'); btn.onclick = function (env) { //console.log(event); // 查看event對象 MouseEvent?{isTrusted: true, screenX: 27, screenY: 160, clientX: 27, clientY: 25,?…} var env = env || window.event; console.log(env) } </script> </html>
需要註意的是,一般情況下,如果一個函數是事件處理函數,那麽推薦將函數的第一個參數設置為事件對象。
我們通過event對象通常情況下可以處理非常多的事件相關的內容。例如,鍵盤事件,例如鼠標事件等等相關的操作。
自定義右鍵菜單
下面是自定義右鍵菜單的案例:
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
body {
font-size: 16px;
font-family: "KaiTi";
}
ul {
list-style: none;
margin:0;
padding: 0;
}
a {
text-decoration: none;
color: #333;
}
.contextmenu {
width: 200px;
border: 1px solid #999;
box-shadow: 3px 3px 3px #ccc;
background-color: #fff;
position: absolute;
top: 10px;
left: 10px;
display: none;
}
.contextmenu li {
height: 38px;
line-height: 38px;
}
.contextmenu li a {
display: block;
padding:0 20px;
}
.contextmenu li a:hover {
background-color: #ccc;
color: white;
font-weight: bold;
}
</style>
</head>
<body>
<div class="contextmenu" id="context">
<ul>
<li><a href="javascript:;">復制</a></li>
<li><a href="javascript:;">粘貼</a></li>
<li><a href="javascript:;">剪切</a></li>
<li><a href="javascript:;">獲取種子</a></li>
<li><a href="javascript:;">迅雷下載</a></li>
</ul>
</div>
</body>
<script>
// 先來獲取菜單列表,然後讓其在鼠標右擊的時候顯示出來
document.oncontextmenu = function (ob) { // ob 表示event事件
// 兼容event事件
var e = ob || window.event;
// 首先獲取菜單
var context = document.getElementById('context');
// 讓菜單顯示出來
context.style.display = "block";
// 讓菜單跟隨鼠標位置而移動
// 需要使用鼠標的坐標,讓鼠標的坐標位置為菜單的左上角0,0
var x = e.clientX;
var y = e.clientY;
// 獲取窗口的寬度和高度(在瀏覽器中的可用窗口寬度和高度,當調整窗口大小的時候,獲取的值也會變)
var w = window.innerWidth;
var h = window.innerHeight;
console.log("窗口寬度為:"+w,"窗口的高度為:"+h);
// 將獲得的值賦值給菜單的右鍵菜單,從而實現讓右鍵菜單會出現在鼠標的位置上
// context.style.left = x + 'px';
// context.style.top = y + 'px';
// 重新調整寬度和高度
context.style.left =Math.min(w - 202,x) + 'px';
context.style.top = Math.min(h - 230,y) + 'px';
// 通過return false關閉系統默認菜單
return false;
}
// 當鼠標單擊之後,希望關閉右鍵菜單
document.onclick = function () {
var contextmenu = document.getElementById('context');
// 讓菜單在單擊之後消失
contextmenu.style.display = 'none';
}
</script>
</html>
獲取鼠標按鍵
在鼠標事件當中,存在有mousedown事件,當我們點擊鼠標的時候,可以觸發這個事件,但是我們該如何判斷具體的鼠標按鍵呢?
我們可以先來打印一下鼠標事件函數裏面的event對象。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
<script>
document.onmousedown = function (env) {
var env = env || window.event;
console.log(env);
}
</script>
</html>
結果如下:
MouseEvent {isTrusted: true, screenX: 373, screenY: 213, clientX: 373, clientY: 78, …}
altKey: false
bubbles: true
button: 0
buttons: 1
cancelBubble: false
cancelable: true
clientX: 373
clientY: 78
composed: true
ctrlKey: false
currentTarget: null
defaultPrevented: false
detail: 1
eventPhase: 0
fromElement: null
isTrusted: true
layerX: 373
layerY: 78
metaKey: false
movementX: 0
movementY: 0
offsetX: 373
offsetY: 79
pageX: 373
pageY: 78
path: (3) [html, document, Window]
relatedTarget: null
returnValue: true
screenX: 373
screenY: 213
shiftKey: false
sourceCapabilities: InputDeviceCapabilities {firesTouchEvents: false}
srcElement: html
target: html
timeStamp: 4162.865000020247
toElement: html
type: "mousedown"
view: Window {postMessage: ?, blur: ?, focus: ?, close: ?, parent: Window, …}
which: 1
x: 373
y: 78
__proto__: MouseEvent
上面這一系列的值,就是打印出來的結果,我們可以通過button
屬性來具體的獲取我們操作的到底是哪個鼠標按鍵。
console.log(env.button);
根據點擊的結果,我們可以分清,左鍵顯示0,中間鍵顯示1,而右鍵顯示2。
在很多操作的時候,我們就可以根據返回給我們的數字來進行鼠標按鍵判斷。
獲取鼠標坐標
通過evnet對象當中的內容,我們可以非常輕易的獲取鼠標的坐標。
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
<script>
document.onmousemove = function (env) {
var env = env || window.event;
console.log(env.clientX,env.clientY); // clientX 鼠標x軸坐標,clientY鼠標y軸坐標
}
</script>
</html>
當鼠標在一個元素中移動時,我們如果想要獲取鼠標在一個元素中的坐標,我們可以采用下面的寫法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.d1 {
width: 300px;
height: 300px;
background-color: #cccccc;
}
</style>
</head>
<body>
<div class="d1"></div>
</body>
<script>
var d1 = document.getElementsByClassName('d1')[0];
d1.onmousemove = function (env) {
var env = env || window.event;
// 鼠標坐標
var mouseX = env.clientX;
var mouseY = env.clientY;
// 元素坐標
var left = this.offsetLeft;
var top = this.offsetTop;
// 獲取鼠標在元素當中的坐標
var d1_mouse_x = mouseX - left ;
var d1_mouse_y = mouseY - top;
console.log('鼠標在元素內的橫坐標是:' + d1_mouse_x + ',縱坐標是:' + d1_mouse_y);
}
</script>
</html>
下面我們來根據鼠標事件和event對象來完成一個案例:圖層拖拽。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>圖層拖拽</title>
<style type="text/css">
.box {
width:200px;
height: 200px;
background-color: orange;
border: 2px solid pink;
cursor: pointer;
position: absolute;
left:100px;
top: 20px;
}
</style>
</head>
<body>
<h1>圖層拖拽</h1>
<hr>
<div class="box" id="box"></div>
</body>
<script type="text/javascript">
// 獲取元素綁定事件
var oBox = document.getElementById("box");
oBox.onmousedown = function (env) {
var env = env || window.event;
// 獲取一下鼠標在div上的位置
var left = env.clientX - oBox.offsetLeft;
var top = env.clientY - oBox.offsetTop;
// 為了方便查看效果,當鼠標點擊之後,改變一下顏色
oBox.style.background = "#999";
oBox.onmousemove = function (env) {
var env = env || window.event;
var x = env.clientX;
var y = env.clientY;
oBox.style.left = (x - left) + 'px';
oBox.style.top = (y - top) + 'px';
}
}
oBox.onmouseup = function () {
oBox.style.background = "orange";
oBox.onmousemove = function (){}
}
</script>
</html>
獲取鍵盤按鍵
我們常用的鍵盤事件有keydown
、keyup
、keypress
三個。
我們綁定了鍵盤事件之後,event對象就會轉換為相應的鍵盤事件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
<script>
document.onkeydown = function (env) {
var env = env || window.event;
console.log(env); // KeyboardEvent
}
</script>
</html>
那麽我們該如何判斷鍵盤按鍵呢?
在鍵盤事件中的event事件中有一個屬性keyCode可以返回鍵盤所對鍵位的ascii碼。
<script type="text/javascript">
// document.onkeydown = function (env) { // 這個事件的缺點是一些符號顯示不出
// // 通過event對象keycode屬性來實現獲取按鍵
// var env = env || window.event;
// console.log(env.keyCode); // 可以得到按鍵對應的ascii碼
// // 可以通過fromCharCode來將ascii碼轉換成對應的字符串
// console.log(String.fromCharCode(env.keyCode));
// console.log("按鍵按下");
// }
document.onkeypress = function (env) {//這個事件可以將字符+符號都顯示出來,但是控制鍵不行
// 通過event對象keycode屬性來實現獲取按鍵
var env = env || window.event;
console.log(env.keyCode); // 可以得到按鍵對應的ascii碼
// 可以通過fromCharCode來將ascii碼轉換成對應的字符串
console.log(String.fromCharCode(env.keyCode));
console.log("按鍵按下");
}
document.onkeyup = function () {
console.log("按鍵擡起");
}
</script>
我們還可以通過env.key
來獲取按鍵信息,下面是一個小demo,通過鍵盤的上下左右來移動元素。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.d1 {
width: 100px;
height: 100px;
background-color: red;
position: absolute;
left: 0;
top: 0;
}
</style>
</head>
<body>
<div class="d1"></div>
</body>
<script>
var d1 = document.getElementsByClassName('d1')[0];
console.log(d1)
document.onkeydown = function (env) {
var env = env || window.event;
// console.log(env.key)
var keybor = env.key;
console.log(keybor)
switch (keybor) {
case 'ArrowUp':
d1.style.top = d1.offsetTop - 5 + 'px';
break;
case 'ArrowDown':
d1.style.top = d1.offsetTop + 5 + 'px';
break;
case 'ArrowLeft':
d1.style.left = d1.offsetLeft - 5 + 'px';
break;
case 'ArrowRight':
d1.style.left = d1.offsetLeft + 5 + 'px';
break;
}
}
</script>
</html>
我們也可以來判斷alt
鍵和ctrl
鍵是否被按下。
document.onmousedown = function (event) {
var env = env || window.event;
console.log(env.altKey); // 當我們進行alt鍵操作的時候,會返回true,否則返回false
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
</body>
<script>
document.onmousedown = function (event) {
var env = env || window.event;
console.log(env.ctrlKey); // 當我們進行ctrl鍵操作的時候,會返回true,否則返回false
}
</script>
</html>
上面我們在判斷按鍵時,使用了keyCode
,我們還可以通過which
來進行判斷。
document.onkeydown = function (event) {
var env = env || window.event;
// console.log(env.ctrlKey); // 當我們進行ctrl鍵操作的時候,會返回true,否則返回false
console.log(String.fromCharCode(env.which))
}
兼容性問題:
IE:
支持keyCode
不支持which和charCode,二者值為 undefined
在Firefox下:
支持keyCode,除功能鍵外,其他鍵值始終為 0
支持which和charCode,二者的值相同
在Opera下:
支持keyCode和which,二者的值相同
不支持charCode,值為 undefined
頁面中位置的獲取
上面我們使用過clientX
和clientY
,通過這兩個屬性,我們可以獲取鼠標的坐標。
在實際的應用中,我們還經常碰到另外一些屬性,
如:
- event.offsetX
- event.clientX
- event.pageX
- event.scrrenX
圖例:
- event.layerX
- event.layerY
- eventX
- eventY
瀏覽器的默認行為
很多時候,我們的瀏覽器都具備一些默認的行為,這些默認的行為在某些時刻我們需要取消或者屏蔽掉,例如當我們在我們自己的網頁中自定義了右鍵菜單,那麽我們就希望屏蔽掉瀏覽器的右鍵菜單,所以我們可以如下:
document.oncontextmenu = function () {
return false;
}
當然,我們也可以采用更加標準的寫法:
if(e.preventDefault){
e.preventDefault();
}else{
window.event.returnValue == false; // 兼容ie
}
我們也可將上面的寫法進行封裝處理:
//阻止瀏覽器的默認行為
function stopDefault( e ) {
//阻止默認瀏覽器動作(W3C)
if ( e && e.preventDefault )
e.preventDefault();
//IE中阻止函數器默認動作的方式
else
window.event.returnValue = false;
return false;
}
冒泡
什麽是冒泡
我們可以先來看下面的案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
div {
padding:40px;
}
#div1 {
background-color: red;
}
#div2 {
background-color: pink;
}
#div3 {
background-color: orange;
}
</style>
</head>
<body>
<div id="div1">
<div id="div2">
<div id="div3"></div>
</div>
</div>
</body>
<script>
var d1 = document.getElementById('div1');
var d2 = document.getElementById('div2');
var d3 = document.getElementById('div3');
function fn1() {
alert(this.id);
}
// 綁定事件
d1.onclick = fn1;
d2.onclick = fn1;
d3.onclick = fn1;
</script>
</html>
在上面的代碼中,會發現,我們點擊時會彈出多個彈窗,為什麽會出現這種情況呢?
原因是因為標簽的物理結構影響了事件,產生了我們看到的結果。
而出現的這種情況,就是我們說的事件冒泡。
事件冒泡:當一個元素接受到事件的時候,會把它接受到的所有傳播給它的父級,一直到頂層window。也就是事件冒泡機制。
我們可以看另一個演示的實例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button id="btn">點擊</button>
</body>
<script>
var btn = document.getElementById('btn');
btn.onclick = function () {
alert(123);
};
document.onclick = function () {
alert(456);
}
</script>
</html>
你會發現在上面的代碼中,我們點擊一下按鈕,就會彈出123,緊接著彈出456.
出現這種情況的原因是因為我們點擊按鈕時,動作從按鈕傳遞到了document,所以二者才會同時觸發。
再回到上面的案例當中,上面案例的結構如下:
<div id="div1">
<div id="div2">
<div id="div3"></div>
</div>
</div>
即使我們將中間的div2註釋掉,你會發現,當我們點擊div3時,同樣出現了div1被觸發。原因如下:
給元素加一個事件,其實嚴謹的說應該是給元素添加事件處理函數。
我們給div1綁定事件,oDiv1.onclick = fn1;告訴div1,如果接受到了一個點擊事件,那麽就去執行fn1。我們稱之這種行為為事件函數綁定。
而我們將oDiv1.onclick = fn1註釋掉後,只是將綁定的事件處理函數給取消掉了,但是並沒有讓它的事件消失。
換個角度說我們點擊任何一個元素,這個元素是否能獲取這個點擊事件呢?
答案是必須的。但是你說為什麽點擊的時候沒什麽發生呢?是因為你沒有綁定發生點擊之後該要辦的事。
事件冒泡是默認存在的,我們在日常的工作的時候,很容易被這個情況所影響到。
例如下面的案例,我們的本意是,點擊按鈕出現一個內容框:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.d1 {
width: 300px;
height: 300px;
border:2px solid red;
display: none;
}
</style>
</head>
<body>
<button id="btn">click me</button>
<div class="d1"></div>
</body>
<script>
var btn = document.getElementById('btn');
var d1 = document.getElementsByClassName('d1')[0];
btn.onclick = function () {
d1.style.display = 'block';
};
// 我們同時希望點擊網頁的其他地方將d1隱藏
document.onclick = function () {
d1.style.display = 'none';
};
</script>
</html>
我們發現似乎很符合 邏輯的情況卻不能實現點擊顯示小框。而這就是我們的事件冒泡所產生。
不妨嘗試將 d1.style.display = ‘none‘; 這句代碼加上定時,你就能夠發現元素是出現然後自動消失的。
而原因就是單擊的動作從btn傳遞到了document。
那麽我們該如何阻止這種行為呢?
可以采用下面這個函數進行阻止冒泡:
function stopBubble(e) {
//如果提供了事件對象,則這是一個非IE瀏覽器
if ( e && e.stopPropagation )
//因此它支持W3C的stopPropagation()方法
e.stopPropagation();
else
//否則,我們需要使用IE的方式來取消事件冒泡
window.event.cancelBubble = true;
}
例如上面的例子:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.d1 {
width: 300px;
height: 300px;
border:2px solid red;
display: none;
}
</style>
</head>
<body>
<button id="btn">click me</button>
<div class="d1"></div>
</body>
<script>
var btn = document.getElementById('btn');
var d1 = document.getElementsByClassName('d1')[0];
btn.onclick = function (e) {
d1.style.display = 'block';
stopBubble(e); // 阻止冒泡
};
// 我們同時希望點擊網頁的其他地方將d1隱藏
document.onclick = function () {
d1.style.display = 'none';
};
function stopBubble(e) {
//如果提供了事件對象,則這是一個非IE瀏覽器
if ( e && e.stopPropagation )
//因此它支持W3C的stopPropagation()方法
e.stopPropagation();
else
//否則,我們需要使用IE的方式來取消事件冒泡
window.event.cancelBubble = true;
}
</script>
</html>
那麽冒泡是否都是壞事呢?也不盡然,我們也可以利用冒泡來實現一些功能,例如下面的分享到的功能:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#div1 {
width: 100px;
height: 200px;
background: red;
position: absolute;
left: -100px;
top: 100px;
}
#div2 {
width: 30px;
height: 70px;
position: absolute;
right: -30px;
top: 70px;
background: #000;
color: #ffffff;
text-align: center;
}
</style>
</head>
<body>
<div id="div1">
<div id="div2">分享到</div>
</div>
</body>
<script>
var d1 = document.getElementById('div1');
d1.onmouseover = function () {
this.style.left = 0;
};
d1.onmouseout = function () {
this.style.left = '-100px';
};
</script>
</html>
上面的代碼中,我們通過給div1設定了事件,但是這個事件卻是被div2傳遞過來的動作所觸發,這種模式我們稱之為事件委托
.
小練習
隔行換色:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul id="list">
<li>aaaaa</li>
<li>aaaaa</li>
<li>aaaaa</li>
<li>aaaaa</li>
<li>aaaaa</li>
</ul>
</body>
<script>
var list = document.getElementById('list').getElementsByTagName('li');
for(var i=0;i<list.length;i++){
list[i].style.backgroundColor = i % 2==0 ? "red" : "green";
}
</script>
</html>
JavaScript基礎入門09