事件
事件对象
- 触发DOM上的某个事件后,会产生一个事件对象event,这个对象包含着所有与事件有关的信息。所有浏览器都支持event对象,但方式有所不同。
DOM中的事件对象
- 兼容DOM的浏览器会将一个event对象传入到事件处理程序中。无论指定事件处理程序使用什么方法(DOM0级或DOM2级),都会传入event对象。
var btn = document.getElementById("btn");
//DOM0级
btn.onclick = function(e) {
alert(e.type);//"click"
}
//这里即使不给第一个参数取别名,直接调用event.type也是可以的,如下
btn.onclick = function(e) {
alert(event.type);//"click"
alert(event == e);//true 这里的event是请求到了window下的event
alert(event == window.event);//true
//window.event = null; 加上这段 下面为false
//alert(event == e);//false
}
//DOM2级
btn.addEventListener("click", function(e) {
alert(e.type);//"click"
});
- 而通过HTML直接指定事件处理程序,变量event中会保存event对象。
<button id="btn" onclick="alert(event.type)">click</button>
//我觉得可以把这块代码想成是
function(event) {
with(document) {
with(this) {
alert(event.type);
}
}
}
//不过这种想象是错的,其实是访问了window.event。
- 下面是event对象的属性和方法:
属性/方法 | 类型 | 读/写 | 说明 |
---|---|---|---|
bubbles | Boolean | 只读 | 表明事件是否冒泡 |
cancelable | Boolean | 只读 | 表明是否可以取消事件的默认行为 |
currentTarget | Element | 只读 | 其事件处理程序当前正在处理事件的那个元素 |
defaultPrevented | Boolean | 只读 | 为true表示已经调用了preventDefault(DOM3级事件新增) |
detail | Integer | 只读 | 与事件相关的细节信息 |
eventPhase | Integer | 只读 | 调用事件处理程序的阶段:1.捕获阶段;2.“处于目标”;3.冒泡阶段 |
preventDefault() | Function | 只读 | 取消事件的默认行为。如果cancelable为true则可以使用这个方法。 |
stopImmediatePropagation | Function | 只读 | 取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用(DOM3级事件新增) |
stopPropagation | Function | 只读 | 取消事件的进一步捕获或冒泡。如果bubbles为true,则可以使用这个方法。 |
target | Element | 只读 | 事件的目标 |
trusted | Boolean | 只读 | 为true表示是浏览器产生的。为false表示是由开发人员通过JS创建的(DOM3级事件新增) |
type | String | 只读 | 触发事件的类型 |
view | AbstractView | 只读 | 与事件关联的抽象视图。等同于发生事件的window对象 |
- 这里说一下this、currentTarget、target的异同点。在事件处理程序内部,对象this始终等于currentTarget的值。而target则是指向触发事件的实际目标。举个例子,当你点击了页面中的一个按钮,在body的事件处理程序中,this和currentTarget都会指向body。但target则指向了按钮。但是在按钮的事件处理程序中,这三个值相等。
<input type="button" id="myBtn" value="Click Me" />
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event.currentTarget === this);//true
alert(event.target === this);//true
};
document.body.onclick = function(event){
alert(event.currentTarget === document.body); //true
alert(this === document.body); //true
alert(event.target === document.getElementById("myBtn")); //true
};
/*btn.addEventListener("click", function (event) {
alert(event.currentTarget === this);//true
alert(this);//按钮。我觉得这个比较神奇,因为按照我的理解这个应该是window
alert(event.target === this);//true
})*/
- type的用处是可以知道该事件属于哪种事件。所以当我们要用同一个方法去处理多种事件类型时,可以判断type的值来执行不一样的代码块。例子省略。
- 要阻止特定事件的默认行为,可以使用preventDefault()方法。例如,链接的默认行为就是在单击时会导航到其href特性指定的URL。我们通过下面的代码可以阻止这种行为。
<a href="http://write.blog.youkuaiyun.com/" id="myLink">Click Me</a>
<script type="text/javascript">
var link = document.getElementById("myLink");
link.onclick = function(event){
alert(event.cancelable);//true代表能够阻止默认行为
event.preventDefault();
};
</script>
- stopPropagation()方法用于停止事件在DOM层次中的传播,即取消进一步的事件捕获或冒泡。例如,在按钮上调用该方法,则可以避免body的事件处理程序的执行(因为这个事件不再冒泡了)。
<input type="button" value="Click Me" id="myBtn" />
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert("Clicked");
alert(event.bubbles);//true 表明事件会冒泡
event.stopPropagation();
};
document.body.onclick = function(event){
alert("Body clicked");
};
</script>
- 书上没有说明event.bubbles(是否冒泡)这个属性对event.stopPropagation()的具体影响。我觉得如果一个事件不会冒泡的话,是不是就意味着该浏览器只会捕获?貌似现代浏览器都支持冒泡,只有一些古代浏览器不支持冒泡。如果抛开这些古代浏览器不讲,只会捕获的浏览器也就意味着默认设置的事件处理程序并不会执行(默认都是在冒泡阶段执行),既然事件本身都不会执行,那停止事件在DOM层次中的传播也就没有意义了。
- 事件对象的eventPhase属性,可以用来确定事件当前处于事件流的哪个阶段。值得一提的是,即使处于目标阶段发生在冒泡阶段,但仍然将其与其他冒泡阶段区别开了。
<input type="button" value="Click Me" id="myBtn" />
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event.eventPhase); //2 处于目标阶段
//这个阶段的target和currentTarget相等。
};
document.body.addEventListener("click", function(event){
alert(event.eventPhase); //1 捕获阶段
}, true);//fasle = 不传 = 默认 = 冒泡
document.body.onclick = function(event){
alert(event.eventPhase); //3 冒泡阶段
};//DOM0级 = 默认 = 冒泡
</script>
- 在事件处理程序执行期间,event对象才会存在。一旦事件处理程序执行完毕,event对象就会销毁。且window.event会根据当前事件流的阶段不断更新。
IE中的事件对象
- 这一部分的主体是IE8-浏览器,IE9+虽然也可以这么用,但是还是推荐用前面说的方法。
- 在IE中访问event对象有几种不同的方式,取决于指定事件处理程序的方法。在使用DOM0级方法添加事件处理程序时,event对象作为window对象的一个属性存在。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event);//IE8- undefined IE9+或者其他浏览器[Object MouseEvent]
event = window.event;
alert(event.type); //2
};
- 当事件是attachEvent()添加的,可以用下面的方法:
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function (e) {
//默认也会有event这个局部变量
// 但是神奇的是在IE中event居然不等于window.event
alert(event == window.event);//false
alert(event.type == window.event.type);//true
//且这两个也不相等
alert(event == e);//false
alert(event.type == e.type);//true
// 且这两个也不相等...厉害了我的哥
alert(window.event == e);//false
})
- 那么问题来了,window.event != e ,我们可以强行认为这种方式在调用事件处理程序时不会动态的改变window.event。那为什么event != window.event,如果这两个不是一个东西,那这个event到底是在哪?按照作用域链的知识,这里event没有报错,那他就只能存在于匿名函数内部或者全局作用域,可是它又和全局作用域下的不同。匿名作用域中又没有指定,这是怎么回事???
先放放,我也不知道原因是什么。。。
如果是HTML特性指定的事件处理程序,这种情况和之前一样,可以直接通过event变量来访问event对象。
<input type="button" value="Click Me" id="myBtn" onclick="alert(event.type);alert(event == window.event)"/>
//弹出是click和false。依旧是false,还是无法解释。
- IE中的event事件对象也包含与创建它的事件相关的属性和方法,不同事件类型属性和方法也有差异,以下是所有事件都包含的一些属性和方法。
属性/方法 | 类型 | 读/写 | 说明 |
---|---|---|---|
cancelBubble | Boolean | 读/写 | 默认值为false,设置为true可以取消事件冒泡(IE8-中事件处理程序只在冒泡阶段执行,与DOM中的stopPropagation()作用相同) |
returnValue | Boolean | 读/写 | 默认值为true,设置为false可以取消事件的默认行为(preventDefault()) |
srcElement | Element | 只读 | 事件的目标(target) |
type | String | 只读 | 被触发的事件的类型 |
- 因为事件处理程序的作用域是根据指定它的方式来确定的,所以不能认为this会始终等于事件目标。故而,最好还是使用event.srcElement比较保险,来看下面的例子:
var btn = document.getElementById("myBtn");
//下面两种方式顺序无关,不会互相覆盖
btn.onclick = function(){
alert(window.event.srcElement === this); //true
alert(this)//这个this指向btn,因为这个函数是btn的一个属性
};
btn.attachEvent("onclick", function(event){
alert(event.srcElement === this); //false
alert(this)//这个this指向window,因为这是一个匿名函数
});
document.onclick = function(){
alert(window.event.srcElement === this); //false 点击的是input
};
- 另外两个属性大同小异。下面是书中的例子,就不解释了。
<a href="http://write.blog.youkuaiyun.com/" id="myLink">Click Me</a>
<script type="text/javascript">
var link = document.getElementById("myLink");
link.onclick = function(){
window.event.returnValue = false;
};
</script>
<input type="button" value="Click Me" id="myBtn" />
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert("Clicked");
window.event.cancelBubble = true;
};
document.body.onclick = function(event){
alert("Body clicked");
};
</script>
跨浏览器的事件对象
- 和前一篇文章末尾说的addHandle()方法类似,我们可以将上面的方法通过能力检测编写出一套跨浏览器的代码。这里不再详解。
var EventUtil = {
getEvent: function(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;
}
}
};