事件对象

事件对象

1.事件对象

事件对象

  • 当事件的响应函数被触发的时候,浏览器每次都会将一个事件对象作为实参传递进相应函数
  • 在事件对象中封装了当前事件相关的一切信息,比如:鼠标的坐标\键盘某按键被按下\鼠标滚轮滚动方向等.

鼠标\键盘属性

<练习:鼠标在areaDiv中移动时,在showMsg中来显示鼠标的坐标>

HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="../../css/reset.css">
    <link rel="stylesheet" href="../../css/normalize.css">
    <link rel="stylesheet" href="p5.css">
    <script defer src="p5.js"></script>
</head>
<body>
    <div id="areaDiv"></div>
    <div id="showMsg"></div>
</body>
</html>

CSS代码

#areaDiv {
    border: 1px solid black;
    width: 300px;
    height:100px;
    margin: 10px auto;
}

#showMsg {
    border:1px solid black;
    width:300px;
    height:20px;
    margin:0 auto;

    text-align: center;
}

JS代码

var areaDiv = document.getElementById("areaDiv");
var showMsg = document.getElementById("showMsg");


areaDiv.onmousemove = function(event){
    /* var x; 
    var y;
    if(event){
        x = event.clientX;
        y = event.clientY;
    }
    else{
        x = window.event.clientX;
        y = window.event.clientY;
    } */
    //兼容IE8 的写法
    event = event || window.event;
    var x = event.clientX;
    var y = event.clientY;
    showMsg.innerHTML = "X = "+ x + ", Y = " + y;
}

效果
image

<练习2:box跟着鼠标移动>
HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="../../css/reset.css">
    <link rel="stylesheet" href="../../css/normalize.css">
    <link rel="stylesheet" href="p6.css">
    <script defer src="p6.js"></script>
</head>
<body>
    <div class="box1" style="left:0; top:0"></div>
</body>
</html>

CSS代码

.box1{
    position: absolute;
    height:200px;
    width:200px;
    background-color: red;
}

javascript代码

var box = document.getElementsByClassName("box1")[0];

box.onmousemove = function(event){
    event = event || windows.event;
    var left = event.clientX;
    var top = event.clientY;

    this.style.left = (left - this.clientWidth / 2) + "px";
    this.style.top = (top - this.clientHeight / 2) + "px";
}

效果
image

2.事件的冒泡

所谓事件的冒泡指的是事件的向上传到,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发.

在开发中大部分情况下冒泡都是有用的,如果不希望发生事件的冒泡可以通过事件对象来取消冒泡.
可以将事件对象的cancelBubble设置为true,即可取消冒泡.
<例子1:事件的冒泡>
HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="../../css/reset.css">
    <link rel="stylesheet" href="../../css/normalize.css">
    <link rel="stylesheet" href="p7.css">
    <script defer src="p7.js"></script>
</head>
<body>
    <div id="box1">
        我是div
        <span id="s1">
            我是span
        </span>
    </div>
</body>
</html>

CSS代码

#box1{
    width:200px;
    height: 200px;
    background-color: brown;
}

#s1{
    background-color:darkgoldenrod;
}

JS代码

document.getElementById("s1").onclick = function() {
    alert("我是span");
}

document.getElementById("box1").onclick = function() {
    alert("我是div");
}

document.body.onclick = function() {
    alert("我是body");
}

document.documentElement.onclick = function(){
    alert("我是HTML");
}

image
取消冒泡的JS代码

document.getElementById("s1").onclick = function(event){
    // 兼容event
    event = event || window.event;
    alert("我是span"); // 我是span
    event.cancelBubble = true;
};

3.事件的委派(Delegate)

事件的委派指的是将事件统一绑定给元素的共同的祖先元素.这样当后代元素上的事件触发时,会一直冒泡到祖先元素,而通过祖先元素的相应函数来处理事件,
事件的委派利用了冒泡,通过委派来减少事件绑定的次数,提高程序的性能.
image

首先我们来看一个例题:
HTML代码

<button type="button" id="btn">Add</button>
<ul id="ulDiv">
    <li><a href="javascript:;" class="link">超链接1</a></li>
    <li><a href="javascript:;" class="link">超链接2</a></li>
    <li><a href="javascript:;" class="link">超链接3</a></li>
</ul>

JS代码

function clickFun(){
    alert("超链接");
}

window.onload = function(){
    // 为每一个超链接都绑定一个单击响应函数
    var aList = document.getElementsByTagName("a");
    for(var i=0;i<aList.length;i++){
        aList[i].onclick = clickFun;
    }
    var btn = document.getElementById("btn");
    var ulDiv = document.getElementById("ulDiv");
    btn.onclick = function(){
        var li = document.createElement("li");
        li.innerHTML = "<a href=\"javascript:;\">add超链接</a>";
        ulDiv.appendChild(li);
    };
};

虽然我们为每一个超链接都绑定了一个单击响应函数,但是这种操作比较麻烦,只能为已有的超链接设置事件,而新添加的超链接必须重新绑定.如果我们希望只绑定一个事件就可以应用到多个元素上,我们就可以用事件的委派.

ulDiv.onclick = function(){
    alert("事件委派超链接");
};

这样虽然单击每个连接都可以触发单击响应函数,但是我们是给整个ul绑定的,在点击ul块内除超链接以外的部分时,也会触发事件,这是我们不想要的,那我们应该怎么做呢?
这个时候我们需要判断一下触发事件的元素是谁,然后再决定执行不执行.

ulDiv.onclick = function(event){
    event = event || window.event;
    // 如果触发事件的对象是我们期望的元素,则执行,则不执行
    // alert(event.target); // 点击超链接外:[object HTMLLIElement]; 点击超链接:javascript:;
    if(event.target.className == "link"){
        alert("事件委派超链接");
    }
};

但是这种写法也存在问题,当一个超链接class不止有link时,就会报错,此时我们可以用targettagName来代替className.

<li><a href="javascript:;" class="link hello">超链接1</a></li> <!-- 失效 -->
<li><a href="javascript:;" class="link">超链接2</a></li>
<li><a href="javascript:;" class="link">超链接3</a></li>
ulDiv.onclick = function(event){
    event = event || window.event;
    if(event.target.tagName == "A" || event.target.tagName == "a"){
        alert("事件委派超链接");
    }
};

4.事件的绑定

使用对象.事件 = 函数的形式绑定相应函数,它只能同时为一个元素的一个事件绑定一个相应函数,如果绑定了多个,后面的会覆盖掉前面的.

var btn = document.getElementById("btn");
// 为btn绑定一个单击响应函数
btn.onclick = function() {
    alert(1);
};
// 为btn绑定第二个响应函数
btn.onclick = function() {
    alert(2); // 2
};

addEventListener() 和attachEvent()

其中addEventListener()是除IE8及以下浏览器可以使用的,而attachEvent()是IE8及以下浏览器支持的.
addEventListener()的参数

  • 事件的字符串,不要on
  • 回调函数,当事件触发时该函数会被调用
  • 是否在捕获阶段触发事件,需要一个布尔值,一般都传false
    attachEvent()的参数
  • 事件的字符串,要on
  • 回调函数
    所以我们需要自己封装一个方法来适应不同的浏览器
// 定义一个函数,用来为指定元素绑定响应函数
// 参数:
// - obj 要绑定事件的对象
// - eventStr 事件的字符串
// - callback 回调函数
function bind(obj, eventStr, callback) {
    if (obj.addEventListener) {
        obj.addEventListener(eventStr, callback, false);
    } else {
        obj.attachEvent("on" + eventStr, callback);
    }
}

但是目前还存在一个问题,这两个对象this所指向的是不一样的.

bind(btn, "click", function() {
    alert(this); // IE8: [object window];非IE8:[object HTMLButtonElement]
});

所以我们可以使用callapply来对bind函数进行优化

function bind(obj, eventStr, callback) {
    if (obj.addEventListener) {
        obj.addEventListener(eventStr, callback, false);
    } else {
        // this是谁由调用方式决定
        // callback.call(obj)
        obj.attachEvent("on" + eventStr, function(){
            // 在匿名函数中调用回调函数
            callback.call(obj);
        });
    }
}

5.事件的传播

事件的传播分为三个阶段

  1. 捕获阶段:在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件.
  2. 目标阶段:事件捕获到目标元素,捕获结束后开始在目标元素上触发事件.
  3. 冒泡阶段:时间从目标元素向他的祖先元素传递,依次触发祖先元素上的事件.
    image
    如果我们希望在捕获阶段就触发事件,可以在addEventListener()的第三个参数中设置为true,一般情况下我们不希望在捕获阶段就触发事件,所以这个参数一般都是false.
    IE8及以下的浏览器没有捕获阶段.

6.拖拽

拖拽的流程

  1. 当鼠标在被拖拽元素上按下时,开始拖拽onmousedown.
  2. 当鼠标移动时被拖拽元素跟随鼠标移动onmousemove.
  3. 当鼠标松开时,被拖拽元素固定在当前位置onmouseup.
    image

setCapture

setCapture可以将鼠标事件锁定在指定的元素上,当元素捕获了鼠标事件后,该事件只能作用在当前元素上。
以下情况会导致事件锁定失败:

  • 当窗口失去焦点时,锁定的事件,自动就会取消。
  • alert也会导致事件的锁定取消。解决办法是在alert之后再次锁定。
  • 鼠标右键也会导致事件解锁。
    使用setCapture可以解决IE8及以下浏览器拖拽网页中内容时,浏览器会默认去搜索引擎中搜索内容,此时会导致拖拽功能的异常.其为IE浏览器特有.使用完以后要releaseCapture

我们把拖拽功能封装成一个函数:

// 拖拽方法封装成一个函数
function draw(obj){
    obj.onmousedown = function(event) {
        obj.setCapture && obj.setCapture();
        event = event || window.event;
        var boxLeft = event.clientX - obj.offsetLeft;
        var boxTop = event.clientY - obj.offsetTop;
        document.onmousemove = function(event) {
            event = event || window.event;
            obj.style.left = event.clientX - boxLeft + "px";
            obj.style.top = event.clientY - boxTop + "px";
        };
        document.onmouseup = function(event) {
            document.onmousemove = null;
            document.onmouseup = null;
            obj.releaseCapture && obj.releaseCapture();
        };
        return false;
    };
}

HTML代码

<div id="box1"></div>
<div id="box2"></div>
<img src="img/an.jpg" id="img" style="width: 320px;height: 320px;position: absolute;left:200px;top:400px;"/>

JS代码调用函数

var box1 = document.getElementById("box1");
var box2 = document.getElementById("box2");
var img = document.getElementById("img");
draw(box1);
draw(box2);
draw(img);
posted @ 2021-09-23 19:17  bleaka  阅读(56)  评论(0)    收藏  举报