Event

189 阅读8分钟

Event是什么? JS中事件的本质是程序各个组成部分之间的一种通信方式,也是异步编程的一种实现。 完整的事件有三个重要的组成部分:

谁触发? 如何触发? 触发之后发生了什么?

var btn = document.getElementById('btn');

​ btn.onclick = function(){ alert('Hello Event!'); } 谁触发:btn元素。 如何触发:click鼠标左键单击。 触发之后发生了什么:回调函数中的业务代码。

Event对象 事件发生以后,会产生一个事件对象,作为参数传给监听函数。 具体的表现就是我们在回调函数中传入一个event形参,这个形参的值是JS自动传入的。 在这个事件对象中会包含这次事件的所有相关信息,包括是什么事件(鼠标/键盘),事件的触发者,事件的目标等等。

btn.onclick = function(event){
    console.log(event);// 将事件对象打印到控制台
}

两个方法

preventDefault():取消浏览器对当前事件的默认行为。 stopPropagation():阻止事件在DOM中继续传播。 鼠标事件

e.clientX/e.clientY e.offsetX/e.offsetY e.pageX/e.pageY 键盘事件

e.altKey/e.ctrlKey/e.metaKey/e.shiftKey e.key/e.keyCode EventTarget接口 DOM 的事件操作(监听和触发),都定义在EventTarget接口。所有节点对象都部署了这个接口。

对于该接口的学习我们只需要了解两个方法:

1,addEventListener(event,callback,flag):绑定事件监听函数

event:事件名称 callback:事件触发时执行的回调函数 flag:布尔值,触发时机(true:事件捕获,false:事件冒泡(默认)) 2,removeEventListener(event,callback,flag):移除事件监听函数,该方法的参数同上

必须是同一个元素节点 参数必须一致 回调函数必须是同一个函数(回调函数需要定义在外面)

// 为btn元素绑定click事件
btn.addEventListener('click',function(){
    alert('Hello Event!');
},false);

​ // 解除btn绑定的事件 btn.removeEventListener('click',function(){alert('Hello Event!');}); 上面的代码我们为btn元素绑定click事件是成功的,但是解除的时候却失败了, 根本原因就是两个函数的参数不一样。 修改后:

// 应该把回调函数定义在方法的外面
function show(){
    alert('Hello Event!');
}
// 为btn元素绑定click事件
btn.addEventListener('click',show,false);

​ // 解除btn绑定的事件 btn.removeEventListener('click',show,false);

事件捕获/事件冒泡 一个事件发生后,会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段。

第一阶段:从window对象传导到目标节点(上层传到底层),称为“捕获阶段”(capture phase)。 第二阶段:在目标节点上触发,称为“目标阶段”(target phase)。 第三阶段:从目标节点传导回window对象(从底层传回上层),称为“冒泡阶段”(bubbling phase)。 第二阶段目标阶段,在目标节点触发事件没什么太多的讲究。 这里我们容易看不懂的是捕获阶段与冒泡阶段。这两个阶段我们通常叫做事件捕获/事件冒泡。 下面代码具体演示:

HTML

<div id="parent">
    <div id="child"></div>
</div>

// 事件冒泡
parent.addEventListener('click',function(){
    alert('parent');
},false);
child.addEventListener('click',function(){
    alert('child');
},false);

​ // 事件捕获 parent.addEventListener('click',function(){ alert('parent'); },true); child.addEventListener('click',function(){ alert('child'); },true); 在上面代码中,只要我们点击的是child那么必然会发生两次弹窗。 冒泡,因为事件的触发规则是从里面往外走的,所以顺序是先child后parent。 捕获,因为事件的触发规则是从外面往里走的,所以顺序是先parent后child。

阻止冒泡

如果我们需要的不是点击子级元素触发两次事件的话(通常也是不需要的),那么我们可以阻止冒泡事件。 具体实现方法就是往回调函数中传入一个event对象的形参,这个形参对应的实参不需要我们手动添加,所以我们只管在函数内部调用就可以了。在event对象下有一个方法:stopPropagation(),这个方法就是专门用来阻止事件冒泡的。

// 事件冒泡
parent.addEventListener('click',function(){
    alert('parent');
},false);
child.addEventListener('click',function(event){
    alert('child');
    event.stopPropagation();
},false);

注意:在开发中我们需要使用兼容的写法。

if (event.stopPropagation){  
    event.stopPropagation();  
}else{  
    event.cancelBubble=true; // IE 
}  

事件代理(委托) 由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)。

先看下列代码:

html

<ul id="list">
    <li>items 01</li>
    <li>items 02</li>
    <li>items 03</li>
    <li>items 04</li>
</ul>

javascript

var ul = document.getElementById('list');
var lis = ul.getElementsByTagName('li');

​ for( var i=0;i<lis.length;i++ ){ lis[i].addEventListener('click',function(){ console.log(this.innerText); },false); } 在上面的代码中我们需要为每一个li都绑定上一个监听事件,这种重复性的操作我们就可以使用事件代理来实现。

ul.addEventListener('click',function(e){
    console.log(e.target.innerText);
},false);

我们利用事件代理取代了之前为每一个li元素都绑定事件监听器的做法,无论从代码的简洁度还是性能上来说都是更加合理的。

事件种类 在JS中的事件可以分为一些种类,针对这些种类我们做了一个总结。

鼠标事件 键盘事件 表单事件 触摸事件 进度事件 拖拽事件 其他事件 详细参考请点击 鼠标事件

click:按下鼠标(通常是按下主按钮)时触发。 dblclick:在同一个元素上双击鼠标时触发。 mousedown:按下鼠标键时触发。 mouseup:释放按下的鼠标键时触发。 mousemove:当鼠标在一个节点内部移动时触发。当鼠标持续移动时,该事件会连续触发。为了避免性能问题,建议对该事件的监听函数做一些限定,比如限定一段时间内只能运行一次。 mouseenter:鼠标进入一个节点时触发,进入子节点不会触发这个事件。 mouseover:鼠标进入一个节点时触发,进入子节点会再一次触发这个事件。 mouseout:鼠标离开一个节点时触发,离开父节点也会触发这个事件。 mouseleave:鼠标离开一个节点时触发,离开父节点不会触发这个事件。 contextmenu:按下鼠标右键时(上下文菜单出现前)触发,或者按下“上下文菜单键”时触发。 wheel:滚动鼠标的滚轮时触发。 键盘事件

keydown:按下键盘时触发。 keypress:按下有值的键时触发,即按下 Ctrl、Alt、Shift、Meta 这样无值的键,这个事件不会触发。对于有值的键,按下时先触发keydown事件,再触发这个事件。 keyup:松开键盘时触发该事件。 表单事件

change:当、、的值发生变化时触发。 input:当<input>、<select>、<textarea>的值发生变化时触发。 select:当在<input>、<textarea>里面选中文本时触发。 invalid:用户提交表单时,如果表单元素的值不满足校验条件,就会触发invalid事件。 reset/submit:这两个事件发生在表单对象 上,而不是发生在表单的成员上。 拖拽(drag) 在浏览器中我们可以对元素进行拖拽动作。拖拽的对象有好几种,包括元素节点、图片、链接、选中的文字等等。在网页中,除了元素节点默认不可以拖拉,其他(图片、链接、选中的文字)都是可以直接拖拉的。 如果让元素可以被拖拽,需要给该元素添加draggable属性,设置值为:true。</p> <pre><code><div id="box" draggable="true"></div> </code></pre> <p>仅仅是给元素添加一个拖拽属性的话还是无法达到我们的需求的,这时候我们需要了解一些关于拖拽的事件:</p> <p>被拖拽元素</p> <p>dragstart:当拖拽开始。 drag:拖拽中。 dragend:拖拽完成。 拖放区域</p> <p>dragenter:当被拖拽元素进入时触发。 dragover:当被拖拽元素在拖放区域移动时触发。 dragleave:当被拖拽元素离开拖放区域时触发。 drop:当被拖拽元素投放到拖拽区域时触发。 DataTransfer</p> <p>DataTransfer是一个接口,该接口的主要功能就是用来传递数据。 该接口为所有的拖拽事件对象都添加了一个dataTransfer属性(e.dataTransfer)。 说的简单点就是每一个拖拽的事件对象下都有一个属性对象:dataTransfer。而在该对象下我们可以使用如下的属性和方法。</p> <p>types:返回数据的格式</p> <p>files:返回已经投放的文件的信息数组</p> <p>1,type:文件类型 2,size:文件大小 3,name:文件名 setData(type):设置指定格式的数据。</p> <p>getData(type,data):返回指定格式的数据。</p> <p>clearData(type):清除指定格式的数据。</p>