事件
- 事件是文档和浏览器窗口中发生的特定的交互瞬间
- 事件可能是用户在某些内容上的点击,鼠标经过某个特定元素或按下键盘上的某些按键,事件还可能是web浏览器中发生的事情,比如说某个web页面加载完成,或者是用户滚动窗口或改变窗口大小。
事件流
- 事件流描述的是从页面中接受事件的顺序,但有意思的是,微软(IE)和网景(Netscape)开发团队居然提出了两个截然相反的事件流概念,IE的事件流是事件冒泡流(event bubbling),而Netscape的事件流是事件捕获流(event capturing)。
- 事件冒泡流:div ==> body ==> html ==> document
- 事件捕获流:document ==> html ==> body ==> div
DOM事件流
image.png// html
<body>
<button>
<span>点击</span>
</button>
</body>
// js
var body =document.querySelector('body');
var button =document.querySelector('button');
var span =document.querySelector('span');
// DOM 0级
// body.onclick=function(){
// console.log('body');
// }
// button.onclick=function(){
// console.log('button');
// }
// span.onclick=function(){
// console.log('span');
// }
// DOM 2级
/**
element.addEventListener(event,function,useCapture);
第一个参数是事件的类型(如“click”或“mousedown”)
第二个参数是事件触发后调用的函数。
第三个参数是个布尔值用于描述事件是冒泡(false)还是捕获(true),该参数是可选的。
*/
body.addEventListener('click',function(){
console.log('body');
},true);
button.addEventListener('click',function(){
console.log('button');
},true);
span.addEventListener('click',function(){
console.log('span');
},true);
// body.addEventListener('click',function(){
// console.log('body');
// },false);
// button.addEventListener('click',function(){
// console.log('button');
// },false);
// span.addEventListener('click',function(){
// console.log('span');
// },false);
阻止冒泡
// 阻止事件冒泡
function stopBubble(e) {
if (e && e.stopPropagation) {
e.stopPropagation(); // W3C
} else {
window.event.cancelBubble = true; // IE
}
}
// 阻止事件默认行为
return false;
event.preventDefault();
事件委托
- 不在事件的发生地(直接 dom)上设置监听函数,而是在其父 元素上设置监听函数,通过事件冒泡,父元素可以监听到子元素上事件的触发,通过判 断事件发生元素 DOM 的类型,来做出不同的响应
- 好处:比较合适动态元素的绑定,新添加的子元素也会有监听函数,也可以有事件触发 机制
移动端300ms点击延迟
-
移动端点击有 300ms 的延迟是因为移动端会有双击缩放的这个操作,因此浏览器在 click 之后要等待 300ms,看用户有没有下一次点击,来判断这次操作是不是双击
-
解决方案
- 通过 meta 标签禁用网页的缩放
<meta name="viewport" content="user-scalable=no">
<meta name="viewport" content="initial-scale=1,maximum-scale=1">
- 调用一些 js 库,比如
FastClick
(推荐),原理:在检测到touchend 事件
的时候,会通过 DOM 自定义事件立即出发模拟一个click 事件
,并把浏览器在300ms之后真正的click事件
阻止掉。 - CSS
touch-action
属性,直接将所有的其他手势事件全都禁用掉,便能达到消除延迟的目的,但是这个属性在很多浏览器中都存在不兼容
的问题,而且当设置完这个属性之后,页面的滚动也会随之被禁用,慎用。
点击穿透
-
使用
touchstart
代替click 事件
引发的问题-
touchstart
是手指触摸屏幕就触发,有时候用户只是想滑动屏幕,却触发了touchstart事件 - 使用
touchstart事件
在某些场景下可能会出现点击穿透的现象。
-
-
点击穿透
click 延时问题还可能引起点击穿透的问题,就是如果我们在一个元素上注册了 touchStart 的监听事件,这个事件会将这个元素隐藏掉,我们发现当这个元素隐藏后,触发了这个元素下的一个元素的点击事件,这就是点击穿透 -
移动端浏览器事件执行的顺序是
touchstart
>touchend
>click
。而click事件有 300ms 的延迟,当touchstart 事件
把 B 元素隐藏之后,隔了 300ms,浏览器触发了click 事件
,但是此时B元素不见了,所以该事件被派发到了 A 元素身上
通用事件侦听器函数
const EventUtils = {
// 视能力分别使用dom0||dom2||IE方式 来绑定事件
// 添加事件
addEvent: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
// 移除事件
removeEvent: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
},
// 获取事件目标
getTarget: function(event) {
return event.target || event.srcElement;
},
// 获取 event 对象的引用,取到事件的所有信息,确保随时能使用 event
getEvent: function(event) {
return event || window.event;
},
// 阻止事件(主要是事件冒泡,因为 IE 不支持事件捕获)
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
},
// 取消事件的默认行为
preventDefault: function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
}
};
网友评论