1. 程式人生 > >JavaScript基礎入門09

JavaScript基礎入門09

view meta borde 鼠標坐標 initial 工作 瀏覽器中 現在 touch

目錄

  • 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>

獲取鍵盤按鍵

我們常用的鍵盤事件有keydownkeyupkeypress三個。

我們綁定了鍵盤事件之後,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

頁面中位置的獲取

上面我們使用過clientXclientY,通過這兩個屬性,我們可以獲取鼠標的坐標。

在實際的應用中,我們還經常碰到另外一些屬性,

如:

  • 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