对于一个html网页来说,html是页面的骨架,css是页面的样式,而js则控制页面元素的行为。本篇我们将学习原生网页界面如何操作元素(监听并绑定事件)。并介绍事件流,事件对象,事件冒泡,以及事件委托这几个点。希望对读者的学习有帮助!
请看以下代码:
<button>方法监听注册事件</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
alert('22');
})
btn.addEventListener('click', function() {
alert('22');
})
</script>
通过上述代码可了解:
第一步:绑定页面元素
第二步:监听器addEventListener
e.addEventListener('事件','回调函数') {}
这里需要注意的是,之前我们写简单的事件绑定,如e.onclick(),e.onmouse等,在新学习的这种写法中,事件写的内容要在原来的基础上把on去掉。
请看以下代码:
divs[1].addEventListener('click', fn);
function fn() {
alert('22');
divs[1].removeEventListener('click',fn);
}
最开始给divs中索引为1的元素绑定了click事件,回调函数为fn。当点击fn后,先弹出‘22’模态框,然后取消了该元素的绑定事件。并执行新的回调函数。
首先从字面上理解,事件流指从页面中接收事件的顺序。。
我们知道,js是单线程的脚本语言(JavaScript是一种解释型的脚本语言,C、C++等语言先编译后执行,而JavaScript是在程序的运行过程中逐行进行解释。),当页面中的DOM元素触发事件,浏览器从Window开始从上往下遍历,来查找整个DOM元素。概括为事件发生时会在元素节点与根节点之间按照特定的顺序传播,路径所经过的所有节点都会收到该事件,这个传播过程即DOM事件流。
事件流模型则可以很直观的从原理来为我们呈现事件流,事件流模型分为两个部分:分别是冒泡型事件流,捕获型事件流。
我们知道,网页中元素很多,大部分元素都有父元素,也有部分元素有子元素,那么我们是不是可以把元素看成一棵树(DOM树):
冒泡型事件流:从DOM树的叶子到根,从下到上,范围从小到大遍历;
捕获型事件流:从DOM树的跟到叶子,从上到下,范围从大到小遍历。
刚刚我们已经了解,js中addEventListener的用法。在介绍完冒泡与捕获后,向大家介绍第三个参数:具体格式如下
e.addEventListener('事件',‘回调函数’,第三个参数)
第三个参数是一个布尔值,默认为false,false对应的是冒泡,true代表的是捕获。
接下来我们利用以下结构来学习捕获与冒泡的具体实例:
捕获阶段,addEventListener的第三个值是true,请看以下代码:
var son = document.querySelector('.son');
son.addEventListener('click', function() {
alert('son');
}, true);//捕获阶段
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, true);//捕获阶段
document.addEventListener('click', function() {
alert('document');
})
对子盒子,父盒子先进行获取,然后再绑定事件。理论上,点击son会弹出son模态框,点击father会弹出father模态框。但在捕获阶段:
点击father时没有任何问题:
点击son时却:
原因:捕获型事件流:从DOM树的跟到叶子,从上到下,范围从大到小遍历。
点击父元素遍历顺序:father
点击子元素遍历顺序:father->son,所以点击子元素时会先出现父元素模态框,再出现子元素模态框。
至于为什么没有出现document的模态框,因为我们没有点document,点的是father所以从father开始遍历。
捕获阶段,addEventListener的第三个值是false(或者不写,因为默认false),请看以下代码:
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
});
var son = document.querySelector('.son');
son.addEventListener('click', function() {
alert('son');
});
document.addEventListener('click', function() {
alert('document');
})
点击father时:
点击son时:
原因:冒泡型事件流:从DOM树的叶子到根,从下到上,范围从小到大遍历。
点击父元素遍历顺序:father->document;
点击子元素遍历顺序: son->father->document。
div是一个盒子,为它绑定事件:
var div = document.querySelector('div');
div.addEventListener('click', function(event){
console.log(event);
})
打印event,结果是一个对象:
我们把event称作事件对象。其中,event可以看作是形参,可以任意更改名字。
这里简单定义一下事件对象:事件对象是事件的一系列相关数据的集合,跟事件相关的,比如鼠标点击的信息,键盘。事件对象存在的前提是事件存在,由系统自动为我们创建。
非常常用!默认行为比如:链接跳转,按钮自动提交等等,我们可以通过事件对象阻止默认行为,下面以阻止链接跳转为例:
e.preventDefault()
var a = document.querySelector('a');
a.addEventListener('click', function(e) {
// e.preventDefault();//方法
// e.returnValue;//属性
return false;//通用,但不能执行后续代码
})
事件冒泡是子到父,当我们为子与父都绑定了点击出现模态框事件,如何取消?见如下代码:
e.stopPropagation();
var father = document.querySelector('.father');
var son = document.querySelector('.son');
father.addEventListener('click', function() {
alert('我是father');
})
son.addEventListener('click', function(e) {
alert('我是son');
e.stopPropagation();
})
即可成功阻止
我们有了事件对象,便可通过事件对象获取鼠标的位置。具体如上图,大家也可以拿下面的代码进行实验:
document.addEventListener('click', function(e) {
console.log(e.clientX);
console.log(e.clientY);
console.log(e.pageX);
console.log(e.pageY);
console.log(e.screenX);
console.log(e.screenY);
})
定义:事件委托(事件代理)。是JavaScript中常用绑定事件的常用技巧。顾名思义,“事件代理”即是把原本需要绑定在子元素的响应事件(click、keydown…)委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。
大家请自行编译如下代码:
<ul>
<li>子元素</li>
<li>子元素</li>
<li>子元素</li>
<li>子元素</li>
<li>子元素</li>
</ul>
<script>
//给父节点添加监听器
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
alert('弹出');
e.target.style.backgroundColor = 'pink';
})
</script>
效果:当我们点击每个子元素li时候,都会弹出模块框‘弹出’。原因:
点击子元素后,由于是冒泡阶段(默认false),所以遍历顺序:子元素->父元素->document。所以,点击子元素后,会触发父元素,于是就会触发模块狂的弹出。
注意:使用“事件委托”时,并不是说把事件委托给的元素越靠近顶层就越好。事件冒泡的过程也需要耗时,越靠近顶层,事件的”事件传播链”越长,也就越耗时。如果DOM嵌套结构很深,事件冒泡通过大量祖先元素会导致性能损失。
本节我们对事件流,事件对象,事件委托等内容进行了讲解。后续会更新更多底层原理及应用,谢谢喜欢,欢迎关注!