最近学习JavaScript事件,对于事件很多东西有点迷糊,综合了各位大佬的文档,来讲一下JS里面事件的相关操作。如果有错误的地方,欢迎大家指正。
事件
HTML 事件可以是浏览器行为,也可以是用户行为。以下是 HTML 事件的实例:
HTML 页面完成加载
HTML input 字段改变时
HTML 按钮被点击
通常,当事件发生时,你可以做些事情。在事件触发时 JavaScript 可以执行一些代码。HTML 元素中可以添加事件属性,使用 JavaScript 代码来添加 HTML 元素。
绑定事件
- 元素中直接绑定;ep:
<button onclick = ""></button>
- DOM事件处理;
①elementObj.event = function(){…};
②addEventListener(“str”,fun(),boo);removeEventListener(“str”,fun(),boo)其中:
1)“str”:事件名称;
2)fun():事件处理的函数
3)boo:捕获(true)或者不捕获(false),默认为false;当boo为true时,元素不发生冒泡行为,事件触发顺寻为捕获的顺序,即从父到子。当boo为false时,元素发生冒泡行为,事件触发为冒泡的顺序。多级层叠时,先执行捕获,再执行冒泡。接下来将以一个简单的例子解释捕获和冒泡。
事件传播的过程:
• 捕获阶段:事件对象从目标的祖先节点Window开始传播直至目标。
• 目标阶段:事件对象传递到事件目标。如果事件的type属性表明后面不会进行冒泡操作,那么事件到此就结束了。
• 冒泡阶段:事件对象以一个相反的方向进行传递,从目标开始,到Window对象结束。
了解了基本概念,那么接下来我们来看看有意思的事情,这里有段代码:
<div id="father">
father
<div id="son">
son
<div id="superson">
super son
<div id="susuperson">susuperson</div>
</div>
</div>
<h3 id="sec_son">sec_son</h3>
</div>
显而易见的,这是一个家族,接下来用addEventListener()为他们添加点击事件:
var father = document.getElementById('father');
var son = document.getElementById('son');
var sec_son = document.getElementById('sec_son');
var superson = document.getElementById('superson');
var susuperson = document.getElementById('susuperson');
father.addEventListener('click', function() {
console.log("father");
});
son.addEventListener('click', function() {
console.log("son");
});
superson.addEventListener('click', function() {
console.log("superson");
});
susuperson.addEventListener('click', function() {
console.log("susuperson");
});
sec_son.addEventListener('click', function() {
console.log("sec_son");
}):
当我们点击susuperson的时候,控制台会给我们输出这样的结果:
那么我们给father的事件添加捕获,即boo设置为true。再次点击susuperson,会发生如下结果:
为了方便理解,再将superson的boo设置为true。再次点击susuperson,结果如下:
如上三个运行结果,可以得出以下结论:当给事件添加捕获之后,该事件会先执行。可以这样理解:事件的三个阶段可以看作是生产可乐的流水线,捕获阶段就是空瓶子过质检,设置了true,就相当于这个瓶子合格了,可以拿去装可乐了。目标阶段就是装好可乐的瓶子拿去装箱,质检没合格的瓶子拿去重铸。冒泡阶段就是将重铸过的瓶子拿去装可乐。
当然了,我们设置的点击事件并没有发生任何改变,只是举个栗子来形容这个输出结果的原因。
如何阻止事件冒泡
阻止事件冒泡拿上面的栗子来说,就是点击susuperson的时候,不让他的父元素发生事件(前提是父元素没有参与捕获)。下面有三种方式:
obj.event(function(eve){
eve.stopPropagation(); //1.停止事件冒泡,但是不会阻止默认行为
return false; // 2.阻止事件冒泡,也阻止了默认行为
eve.preventDefault(); // 3.阻止默认行为,不阻止事件冒泡
});
事件委托
事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。这个栗子最好解释什么是事件委托:
有三个同事预计会在周一收到快递。为签收快递,有两种办法:一是三个人在公司门口等快递;二是委托给前台MM代为签收。现实当中,我们大都采用委托的方案(公司也不会容忍那么多员工站在门口就为了等快递)。前台MM收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款。这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台MM也会在收到寄给新员工的快递后核实并代为签收。
这里其实还有2层意思的:
第一,现在委托前台的同事是可以代为签收的,即程序中的现有的dom节点是有事件的;
第二,新员工也是可以被前台MM代为签收的,即程序中新添加的dom节点也是有事件的。
看下面的代码:
<ul id="ul1">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li></ul>
<script>
window.onload = function(){
var oUl = document.getElementById("ul1");
var aLi = oUl.getElementsByTagName('li');
for(var i=0;i<aLi.length;i++){
aLi[i].onclick = function(){
alert(123);
}
}
</script>
当我们需要给每一个li元素添加点击事件时,第一个想到的就是循环,众所周知,每有一次DOM操作,就会消耗内存,如果我们有1000个li,用这样的方式添加事件,页面还没有加载完呢,用户就已经投诉了。所以可以利用冒泡来完成这件事。
Event对象提供了一个属性叫target,可以返回事件的目标节点,我们成为事件源,也就是说,target就可以表示为当前的事件操作的dom,但是不是真正操作dom,当然,这个是有兼容性的,标准浏览器用ev.target,IE浏览器用event.srcElement,此时只是获取了当前节点的位置,并不知道是什么节点名称,这里我们用nodeName来获取具体是什么标签名,这个返回的是一个大写的,我们需要转成小写再做比较
window.onload = function(){
var oUl = document.getElementById("ul1");
oUl.onclick = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
alert(123);
alert(target.innerHTML);
}
}
}