javascript高级程序设计笔记-第十三章(事件)

时间:2021-10-24 10:25:34

一、事件流

事件流包括三个阶段:事件捕获阶段、处于目标阶段、时间冒泡阶段。

如图:捕获阶段是逐级向下,由不具体到具体节点;冒泡阶段是逐级向上传播到不具体的节点

javascript高级程序设计笔记-第十三章(事件)

二、事件处理程序

1、HTML事件处理程序

通过使用一个与相应事件处理程序同名的HTML特性来指定

<input type="button" value="click" onclick="alert('hi')">

2、DOM0级事件处理程序

将一个函数赋值给一个事件处理程序属性(每个元素都有自己的事件处理程序属性)

var btn = document.getElementById("myBtn");
btn.onclick = function() {
    alert("hi");
};

使用DOM0级方法指定的事件处理程序是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行,即this引用当前的元素

var btn = document.getElementById("myBtn");
btn.onclick = function() {
    alert(this.id);
};

删除事件处理程序

btn.onclick = null;

3、DOM2级事件处理程序

addEventListener()removeEventListener()用于处理指定和删除事件处理程序的操作。接收3个参数:事件名、事件处理函数、布尔值。如果布尔值是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。

var btn = document.getElementById('myBtn');
btn.addEventListener("click", function() {
    alert(this.id);
}, false);
//事件处理程序是在元素的作用域中运行,即this引用当前的元素

通过addEventListener()添加的事件处理程序只能用removeEventListener()移除;移除时传入的参数与添加处理程序时使用的参数相同。(添加的匿名函数无法移除)

var btn = document.getElementById('myBtn');
btn.addEventListener("click", function() {
    alert(this.id);
}, false);
btn.removeEventListener("click", function() {
    alert(this.id);
}, false);      //无效

//将匿名函数赋值给变量
var btn = document.getElementById('myBtn');
var handler = function() {
    alert(this.id);
};
btn.addEventListener("click", handler, false);
btn.removeEventListener("click", handler, false);   //有效

4、IE事件处理程序(IE8及更早版本)

attachEvent()detachEvent(),接收2个参数:事件名、事件处理函数

除了事件处理程序的作用域不一样外,其他类似。IE事件处理程序在全局作用域中运行

var btn = document.getElementById('myBtn');
var handler = function() {
    alert(this === window);
};
btn.attachEvent("onclick", handler);    //true
btn.detachEvent("onclick", handler);

5、跨浏览器的事件处理程序

var EventUtil = {
    addHandler: function(element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    removeHandler: function(element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    }
};

//使用EventUtil对象
var btn = document.getElementById('myBtn');
var handler = function() {
    alert("hi");
};
EventUtil.addHandler(btn, "click", handler);

三、事件对象

1、DOM中的事件对象

在事件处理程序内部,对象this始终等于currentTarget的值,而target则只包含事件的实际目标

如果将事件处理程序指定给了目标元素,则this、currentTarget、target包含的值相同

var btn = document.getElementById('myBtn');
btn.onclick = function(event) {
    alert(this === event.currentTarget);    //true
    alert(this === event.target);           //true
};

如果事件处理程序存在于父节点中,单击当前元素时

var btn = document.getElementById('myBtn');
document.body.onclick = function(event) {
    alert(document.body === event.currentTarget);   //true
    alert(document.body === this);                  //true
    alert(btn = event.target);                      //true
};

使用type属性,通过一个函数处理多个事件

var btn = document.getElementById('myBtn');
var handler = function(event) {
    switch(event.type) {
        case "click":
            alert("hi");
            break;
        case "mouseover":
            event.target.style.backgroundColor = "red";
            break;
        case "mouseout":
            event.target.style.backgroundColor = "";
            break;
    }
};

btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;

preventDefault()方法,阻止特定事件的默认行为(只有在cancelable属性为true时才能使用)

var link = document.getElementById('myLink');
link.onclick = function(event) {
    event.preventDefault();
};

stopPropagation()方法,取消事件的进一步捕获和冒泡(只有在cancelable属性为true时才能使用)

var btn = document.getElementById('myBtn');
btn.onclick = function(event) {
    alert("hi");
    event.stopPropagation();
};
document.body.onclick = function(event) {
    alert("hi again");
};
//如果不使用stopPropagation(),单击按钮时,就会先后出现两次警告框

2、IE中的事件对象

在使用DOM0级方法添加事件处理程序时,event对象作为window对象的一个属性存在。即window.event

var btn = document.getElementById('myBtn');
btn.onclick = function(event) {
    var event = window.event;
    alert(event.type);
};
//通过window.event取得event对象

使用attachEvent()添加事件处理程序时,event对象作为参数被传入事件处理函数

var btn = document.getElementById('myBtn');
btn.attachEvent("onclick", function(event) {
    alert(event.type);
});

srcElement属性,表示事件的目标(与DOM中的target属性相同)

var btn = document.getElementById('myBtn');
btn.onclick = function() {
    alert(window.event.srcElement === this);    //true
};
//都指向btn元素
btn.attachEvent("onclick", function(event) {
    alert(event.srcElement === this);           //false
});
//event.srcElement指向btn元素,this指向全局作用域window

returnValue属性,默认为true,设置为false时可以取消事件的默认行为(与DOM中的preventDefault()方法相同)

var link = document.getElementById('myLink');
link.onclick = function() {
    window.event.returnValue = false;
};

cancelBubble属性,与DOM中的stopPropagation()方法类似,默认为false,设置为true时可以取消事件的冒泡

var btn = document.getElementById('myBtn');
btn.onclick = function() {
    alert("hi");
    window.event.cancelBubble = true;
};
document.body.onclick = function() {
    alert("hi again");
};
//设置为true,单击按钮,只显示一个警告框

3、跨浏览器的事件对象

var EventUtil = {
    getEvent: function(event) {                 //取得event对象
        return event ? event : window.event;
    },
    getTarget: function(event) {                //取得事件的目标
        return event.target || event.srcElement;
    },
    preventDefault: function(event) {           //阻止事件的默认行为
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    stopPropagation: function(event) {          //阻止事件流
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    }
};

四、事件委托

只指定一个事件处理程序,就可以管理某一类型的所有事件

<ul id="myLinks">
    <li id="dosomething">do something</li>
    <li id="gosomewhere">go somewhere</li>
    <li id="sayhi">say hi</li>
</ul>

传统:

var item1 = document.getElementById('dosomething');
var item2 = document.getElementById('gosomewhere');
var item3 = document.getElementById('sayhi');

EventUtil.addHandler(item1, "click", function(event) {
    document.title = "other title";
});
EventUtil.addHandler(item2, "click", function(event) {
    location.href = "http://baidu.com";
});
EventUtil.addHandler(item3, "click", function(event) {
    alert("hi");
});

事件委托:

var list = document.getElementById('myLinks');
EventUtil.addHandler(list, "click", function(event) {
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);
    switch(target.id) {
        case "dosomething":
            document.title = "other title";
            break;
        case "gosomewhere":
            location.href = "http://baidu.com";
            break;
        case "sayhi":
            alert("hi");
            break;
    }
});