JavaScript与HTML交互系列--事件流(冒泡、捕获、应用)和事件处理程序

栏目: Html · 发布时间: 5年前

内容简介:当浏览器发展到第四代时(IE4及Netscape Communicator4),浏览器开发团队遇到了一个很有意思的问题:页面的哪一部分会拥有某个特定的事件?要明白这个问题问的是什么,可以想象画在一张纸上的一组同心圆。如果你把手指放在圆心上,那么你的手指指向的不是一个圆,而是纸上的所有圆。两家公司的浏览器开发团队在看待浏览器事件方面还是一致的。如果你单击了某个按钮,他们都认为单击事件不仅仅发生在按钮上。换句话说,在单击按钮的同时,你也单击了按钮的容器元素,甚至也单击了整个页面。事件流描述的是从页面中接收事件的

当浏览器发展到第四代时(IE4及Netscape Communicator4),浏览器开发团队遇到了一个很有意思的问题:页面的哪一部分会拥有某个特定的事件?要明白这个问题问的是什么,可以想象画在一张纸上的一组同心圆。如果你把手指放在圆心上,那么你的手指指向的不是一个圆,而是纸上的所有圆。两家公司的浏览器开发团队在看待浏览器事件方面还是一致的。如果你单击了某个按钮,他们都认为单击事件不仅仅发生在按钮上。换句话说,在单击按钮的同时,你也单击了按钮的容器元素,甚至也单击了整个页面。

事件流描述的是从页面中接收事件的顺序。但有意思的是,IE和Netscape开发团队居然提出了差不多是完全相反的事件流的概念。IE的事件流是事件冒泡流,而Netscape Communicator的事件流是事件捕获流。

思考:点击页面元素,什么样的元素能感应到这样一个事件?

点击页面元素的同时,也点击了元素的容器元素甚至整个页面。

事件冒泡

IE的事件流叫做 事件冒泡 (event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。

事件捕获

Netscape Communicator 团队提出的另一种事件流叫做 事件捕获 (event capturing)。其思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于事件到达预订目标之前捕获它。

DOM 事件流

“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,( 一般情况下,程序 )可以在冒泡阶段对事件作出响应。

JavaScript与HTML交互系列--事件流(冒泡、捕获、应用)和事件处理程序

事实上,DOM事件流在捕获阶段和冒泡阶段均可触发事件处理程序。捕获阶段先收到事件流

JavaScript与HTML交互系列--事件流(冒泡、捕获、应用)和事件处理程序

对上面元素添加事件绑定程序。

var outBox = document.getElementById("outBox");
var middleBox = document.getElementById("middleBox");
var innerBox = document.getElementById("innerBox");

outBox.addEventListener('click', function() {
    console.log('outBox捕获');
}, true);
middleBox.addEventListener('click', function() {
    console.log('middleBox捕获');
}, true);
innerBox.addEventListener('click', function() {
    console.log('innerBox捕获');
}, true);

outBox.addEventListener('click', function() {
    console.log('outBox冒泡');
}, false);
middleBox.addEventListener('click', function() {
    console.log('middleBox冒泡');
}, false);
innerBox.addEventListener('click', function() {
    console.log('innerBox冒泡');
}, false);

// 输出顺序
// 1 outBox捕获
// 2 middleBox捕获
// 3 innerBox捕获
// 4 innerBox冒泡
// 5 middleBox冒泡
// 6 outBox冒泡
复制代码

IE9、Opera、Firefox、Chrome和Safari( 也就是说当下主流浏览器 )都支持DOM事件流;IE8及更早版本不支持DOM事件流。

思考一下:事件冒泡和事件捕获在日常开发中有哪些应用场景?

我们下面先看一下事件处理程序。

事件处理程序

1. HTML 事件处理程序

为元素添加(事件)属性,值为事件处理程序。

注:事件属性全部为小写。

<div class="outBox" onclick="alert('outBox')">
    <div class="innerBox" onclick="showInnerBox()"></div>
</div>

<script>
    function showInnerBox() {
        alert("innerBox");
    }
</script>
复制代码

特点:传统方式,简单,跨浏览器

2. DOM0 级事件处理程序

使用JavaScript指定事件处理程序,首先必须取得一个要操作的对象的引用。

<div class="outBox" id="outBox">
    <div class="innerBox" id="innerBox"></div>
</div>

<script>
    var outBoxElement = document.getElementById('outBox');
    outBoxElement.onclick = function() {
        alert(this.id)
    }
    // 删除事件处理程序
    outBoxElement.onclick = null
</script>
复制代码

特点:可通过 this 访问元素的任何属性和方法(HTML事件处理程序也可以),可以删除事件处理程序

3. DOM2 级事件处理程序

“DOM2级事件”定义了两个方法,用于处理指定和删除事件处理程序的操作: addEventListener()removeEventLintener() 。所有DOM结点中都包含这两个方法,并且他们都接受3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值如果是 true ,表示在捕获阶段调用事件处理程序;如果是 false ,表示在冒泡阶段调用事件处理程序。

// 添加事件绑定
outBoxElement.addEventListener('click', showOutBox, false);
// 移除事件绑定
outBoxElement.removeEventListener('click', showOutBox);
// 下面移除事件绑定方式无效,无法移除绑定的匿名函数
outBoxElement.removeEventListener('click', function() {
    alert(this.id);
});
复制代码

4. IE 事件处理程序

IE实现了与DOM中类似的两个方法:attachEvent() 和 detachEvent()。这两个方法接受相同的两个参数:事件名称和事件处理函数。由于IE8及更早版本只支持事件冒泡,所以通过attachEvent()添加的事件处理程序都会被添加到冒泡阶段。

var btn = document.getElementById('MyBtn');
btn.attachEvent('onclick', function() {
    console.log('clicked');
});

var handler = function() {
    console.log('clicked');
}
// 第二个参数必须是具名函数,不能是匿名函数
btn.detachEvent('onclick', handler);
复制代码

注:attachEvent() 的第一个参数是'onclick',而非DOM的addEventListener()方法中的'click'。

在IE中使用attachEvent()与使用DOM0级方法的主要区别在于时间处理程序的作用域。 在使用DOM0级方法的情况下,事件处理程序会在其所属元素的作用域内运行;在使用attachEvent()方法的情况下事件处理程序会在全局作用域中运行,因此this等于window

btn.attachEvent('onclick', function() {
    console.log(this === window); // true
})
复制代码

此外,attachEvent() 与addEventListener() 类似均可以为一个元素添加多个事件处理程序。

// 为同一个元素添加多个事件处理程序
btn.addEventListener('click', function() {
    console.log('clicked');
}, false);
btn.addEventListener('click', function() {
    console.log('hello world');
}, false);

btn.attachEvent('onclick', function() {
    console.log('clicked');
});
btn.attachEvent('onclick', function() {
    console.log('hello world');
});
复制代码

5. 跨浏览器事件处理程序

跨浏览器事件处理程序即一套可以同时运行在IE以及非IE浏览器的程序,重点是浏览器能力检测也就是浏览器兼容性检查。

var EventUtil = {
    // 添加事件绑定(元素,事件类型,事件处理函数)
    addHandler: function(element, type, handler) {
        if(element.addEventListenter) {
            // DOM2级绑定事件
            element.addEventListenter(type, handler, false);
        }else if(element.attachEvent) {
            // IE绑定事件
            element.attachEvent('on' + type, handler)
        }else {
            // DOM0级绑定事件,兼容IE8及更早版本
            element['on' + type] = handler;
        }
    },
    // 删除事件事件绑定(元素,事件类型,事件处理函数)
    removeHandler: function() {
        if(element.addEventListenter) {
            // DOM2级删除绑定事件
            element.removeEventListenter(type, handler, false);
        }else if(element.attachEvent) {
            // IE删除绑定事件
            element.detachEvent('on' + type, handler)
        }else {
            // DOM0级删除绑定事件,兼容IE8及更早版本
            element['on' + type] = null;
        }
    }
}

var btn = document.getElementById('MyBtn');
var handler = function() {
    console.log('clicked');
}
// 添加绑定事件
EventUtil.addHandler(btn, 'click', handler);
复制代码

事件冒泡应用-事件委托/代理

对“事件处理程序过多”问题的解决方案就是 事件委托 。事件委托利用了 事件冒泡 ,只指定一个事件处理程序,就可以管理一类型的所有事件。例如,click事件会一直冒泡到document层次。也就是说我们可以为整过页面(一般是某几个元素的父元素)指定一个onclick事件处理程序,而不必给每个可单击的元素分别添加事件处理程序。

<ul id="items">
    <li id="item1">item1</li>
    <li id="item2">item2</li>
    <li id="item3">item3</li>
</ul>
复制代码
var itemList = document.getElementById('items');
EventUtil.addHandler(itemList, 'click', function(e) {
    var id = e.target.id;
    switch(id) {
        case "item1":
            alert('item1 is clicked!');
            break;
        case "item2":
            alert('item2 is clicked!');
            break;
        case "item3":
            alert('item3 is clicked!');
            break;
        case "items":
            alert('items is clicked!');
            break;
    }
});
复制代码

以上所述就是小编给大家介绍的《JavaScript与HTML交互系列--事件流(冒泡、捕获、应用)和事件处理程序》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

密码朋克

密码朋克

[澳] 朱利安·阿桑奇 / Gavroche / 中信出版社 / 2017-10 / 42.00元

互联网已经在世界各地掀起了革命,然而全面的打击也正在展开。随着整个社会向互联网迁移,大规模监控计划也正在向全球部署。我们的文明已经来到一个十字路口。道路的一边通往一个承诺“弱者要隐私,强 者要透明”的未来,而另一边则通往一个极权的互联网,在那里,全人类的权力被转移给不受问责的间谍机构综合体及其跨国公司盟友。 密码朋克是一群倡导大规模使用强密码术以保护我们的基本自由免遭攻击的活动家。维基解密的......一起来看看 《密码朋克》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换