#ThoughtWorkers好声音#第十五期 (图片:网络) 有些东西称为基本功,对于 Web 开发而言,事件处理模型便是其中的一个,我们经常会在代码里遇到阻止浏览器默认行为的做法。 成都办公室的陈致豪花了时间,把事件处理模型整理清楚,做了一次《浏览器默认行为执行与阻止分析》,帮我们更好地理解发生的一切。
var btn = document.getElementByID("myBtn");
btn.onclick = function(){
console.log("this.id"); //myBtn
}
btn.onclick = null; //解绑事件
DOM0的事件流为冒泡类型。
var btn = document.getElementByID("myBtn");
btn.addEventListener("click", function(){
console.log("click");
},false);
unbind中需要注意的一点,如果我们采用:
btn.removeEventListener("click", function(){
console.log("click");
},false);
这样是无法解绑的。原因很简单,传入匿名函数与bind时的匿名函数并非同一函数。为了正确解绑,需要在绑定时不使用匿名函数:
var handler = function(){console.log("click");};
btn.addEventListener("click", handler, false);
btn.removeEventListener("click",handler,false);
相较DOM0级方法, DOM2级方法的优势为:
需要注意的一点是IE仅从IE9开始支持DOM2级事件处理方式。
IE(以及Opera)实现了attachEvent()和detachEvent()方法进行事件绑定与解绑,绑定事件会被添加到冒泡阶段。
var handler = function()
console.log(this === window); //will output "true"
};
btn.attachEvent("onclick",handler); //bind
btn.detachEvent("onclick",handler); //unbind
需要注意的几点:
相信大家对于event对象的三个方法已经非常熟悉: preventDefault(), stopPropagation(), stopImmediatePropagation()。
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript" src="js/script.js"></script>
</head>
<body>
<ul id="parent_element">
<ul>parent</ul>
<ul>
<li><a id="google" href="www.google.com">1</a></li>
<li><a id="douban" href="www.douban.com">2</a></li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</ul>
</body>
</html>
js/script.js:
$(function () {
$('#parent_element').click(function (e) {
e.preventDefault();
console.log("parent element has been clicked," + e.target);
})
$('#parent_element #douban').click(function (e) {
console.log("#douban is clicked");
e.stopPropagation();
})
$('#parent_element #google').click(function (e) {
console.log("google is clicked");
})
})
如上的代码,第一个a是无法进行页面跳转的。第二个a元素可以完成浏览器的默认行为,进行页面跳转。 这里有一个很容易被大家忽视的问题:子节点的浏览器默认行为,被父节点的event.preventDefault() 阻止了。通过对子节点的stopPropagation才可以防止父节点阻止子节点的浏览器默认行为。
首先我们需要明确的一点是event对像的生存周期为:
当每一段事件处理程序执行完后,检测事件是否能继续冒泡,如无法继续冒泡,则进行销毁。如果能继续冒泡,则继续传递事件至顶,完成用户绑定事件处理后,进行事件销毁。
而在event对象被销毁之前,会检测event对象是否执行了event.preventDefault()。在JavaScript中这个boolean值为event.defaultPrevented,jQuery中event对象经过包装,此属性被包装为event.isDefaultPrevented()。如果答案为否,没有执行过event.preventDefault(), 那么此event的浏览器默认行为将被执行。
这个解答对应StackOverflow上的一个问题。