js-事件基础
@
① 事件概述
事件是可以被 JavaScript 侦测到的行为(触发--- 响应机制)。
网页中的每个元素都可以产生某些可以触发 JavaScript 的事件, 例如, 我们可以在用户点击某按钮时产生一个事件,然后去执行某些操作。
② 事件三要素
1. 事件源#
触发事件的节点对象
2. 事件类型#
常见鼠标事件#
鼠标事件 | 触发条件 |
---|---|
onclick | 鼠标点击左键触发 |
ondblclick | 鼠标双击触发 |
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onmouseenter | 鼠标经过触发 |
onmouseleave | 鼠标离开触发 |
onfocus | 获得鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
contextmenu | 鼠标右键菜单触发 |
selectstart | 鼠标开始选中时触发 |
contextmenu#
contextmenu
主要控制应该何时显示上下文菜单,主要用于开发者取消默认的上下文菜单
document.addEventListener('contextmenu', function(e) {
e.preventDefault();//禁止事件默认行为
})
selectstart#
主要用于禁止鼠标选中( selectstart 开始选中)
document.addEventListener('selectstart', function(e) {
e.preventDefault();//禁止事件默认行为
})
两种鼠标经过离开事件的区别#
//eg
var father = document.querySelector('.father');
var son = document.querySelector('.son');
father.addEventListener('mouseover', function() {
console.log('over');
})
father.addEventListener('mouseout',function(){
console.log('out');
})
father.addEventListener('mouseenter', function() {
console.log('enter');
})
father.addEventListener('mouseleave',function(){
console.log('leave');
})
-
onmouseover \ onmouseout
它们都会冒泡,当子节点触发事件时,事件流流到父节点并执行父节点绑定的监听器。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TBMtMFvL-1630226220918)(WebAPIs.assets/a.gif)]
-
onmouseenter \ onmouseleave
它们不会冒泡,子节点触发事件不会执行父节点的监听器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JvKqbJM8-1630226220923)(WebAPIs.assets/b.gif)]
移动端click事件的延时问题#
移动端 click
事件会有 300ms 的延时,原因是移动端屏幕双击会缩放(double tap to zoom) 页面。
解决方案:
-
禁用缩放。 浏览器禁用默认的双击缩放行为并且去掉 300ms 的点击延迟。
<meta name="viewport" content="user-scalable=no">
-
利用touch事件自己封装这个事件解决 300ms 延迟。
原理:
- 当我们手指触摸屏幕,记录当前触摸时间
- 当我们手指离开屏幕, 用离开的时间减去触摸的时间
- 如果时间小于150ms,并且没有滑动过屏幕, 那么我们就定义为点击
//封装tap,解决click 300ms 延时 function tap (obj, callback) { var isMove = false; var startTime = 0; // 记录触摸时候的时间变量 obj.addEventListener('touchstart', function (e) { startTime = Date.now(); // 记录触摸时间 }); obj.addEventListener('touchmove', function (e) { isMove = true; // 看看是否有滑动,有滑动算拖拽,不算点击 }); obj.addEventListener('touchend', function (e) { if (!isMove && (Date.now() - startTime) < 150) { // 如果手指触摸和离开时间小于150ms 算点击 callback && callback(); // 执行回调函数 } isMove = false; // 取反 重置 startTime = 0; }); } //调用 tap(div, function(){ // 执行代码 });
-
fastclick
插件解决 300ms 延迟。 使用延时使用步骤:
-
引入js文件
-
在相关js文件中引入如下语句
if ('addEventListener' in document) { document.addEventListener('DOMContentLoaded', function() { FastClick.attach(document.body); }, false); } //此时,click事件就不会有延时问题 element.addEventListener('click', function() { alert(11); })
-
ondblclick双击事件默认选中问题#
比如双击一个元素节点(事件源)里的文本时,会默认把文本选中
解决方案:在监听函数里写上如下代码即可解决文本默认选中的特性
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
常见的键盘事件#
键盘事件 | 触发条件 |
---|---|
onkeyup | 某个键盘被松开时触发 |
onkeydown | 某个键盘被按下时触发 |
onkeypress | 某个键盘按键被按下时并弹起时触发 |
注意:
- onkeypress 和前面2个的区别是,它不识别功能键,比如左右箭头, shift 等。
滚动事件onscroll#
滚动条在滚动时会触发 onscroll
事件。
触屏事件#
触屏事件概述#
移动端浏览器兼容性较好,我们不需要考虑以前 JS 的兼容性问题,可以放心的使用原生 JS 书写效果,但是移动端也有自己独特的地方。比如触屏事件 touch(也称触摸事件),Android和 IOS 都有。
touch 对象代表一个触摸点。触摸点可能是一根手指,也可能是一根触摸笔。触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作。
常见触屏事件#
触屏touch事件 | 说明 |
---|---|
touchstart | 一个DOM元素上出现触点时触发 |
touchmove | 触点在一个DOM元素上滑动时触发 |
touchend | 触点在一个DOM元素上移开时触发 |
touchmove 触点移动事件默认也会触发页面滚动事件,若页面宽高超出屏幕,随着触点的移动页面也会移动
过度事件#
transitionend#
transitionend - Web API 接口参考 | MDN (mozilla.org)
change事件#
change - Web API 接口参考 | MDN (mozilla.org)
表单事件#
form.submit#
oninput#
GlobalEventHandlers.oninput - Web API 接口参考 | MDN (mozilla.org)
3. 监听器(事件处理程序 )#
事件触发后要执行的代码(函数形式),事件处理函数
<body>
<button id="btn">唐伯虎</button>
<script>
// 点击一个按钮,弹出对话框
// 1. 事件是有三部分组成 事件源 事件类型 事件处理程序 我们也称为事件三要素
//(1) 事件源 事件被触发的对象 谁 按钮
var btn = document.getElementById('btn');
//(2) 事件类型 如何触发 什么事件 比如鼠标点击(onclick) 还是鼠标经过 还是键盘按下
//(3) 事件处理程序 通过一个函数赋值的方式 完成
btn.onclick = function() {
alert('点秋香');
}
</script>
</body>
③ 执行事件的步骤
- 获取事件源
- 注册事件(绑定事件)
- 添加事件处理程序(采取函数赋值形式)
<!-- 案例:点击按钮弹出警示框 -->
<html>
<button id="btn"> hello </button>
</html>
<script>
//1
var btn = document.getElementById('btn');
//2
//btn.onclick;
//3
btn.onclick = function() {
alert('world');
}
</script>
④ 注册事件(绑定事件)
给元素添加事件,称为注册事件或者绑定事件。
1. 传统注册方式#
<button onclick=" alert('hi~')"></button>
btn.onclick = function() {
//...
}
同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数,这是传统注册事件的唯一性
兼容性较好
2. 方法监听注册方式#
addEventListener()#
- 语法
eventTarget.addEventListener(type, listener, useCapture)
-
作用:该方法将指定的监听器注册到 eventTarget( 目标对象)上,当该对象触发指定的事件时, 就会执行事件处理函数。
-
参数 说明 type
事件类型字符串, 比如 click 、 mouseover , 注意这里不要带 on listener
事件处理函数, 事件发生时,会调用该监听函数 useCapture
可选参数, 是一个布尔值,默认是 false;表示事件流 -
特点:
- 同一个元素同一个事件可以注册多个监听器(事件处理函数)按注册顺序依次执行。
- IE9 之前的 IE 不支持此方法
attachEvent ()#
-
语法
eventTarget.attachEvent(eventNameWithOn, callback)
-
作用:该方法方法将指定的监听器注册到 eventTarget(目标对象) 上,当该对象触发指定的事件时, 指定的回调函数就会被执行。
-
参数 说明 eventNameWithOn
事件类型字符串,比如 onclick 、 onmouseover ,这里要带 on callback
事件处理函数,当目标触发事件时回调函数被调用 -
特点
- 同一个元素同一个事件可以注册多个监听器按注册顺序依次执行。
- IE8 及早期版本支持
3.) 注册事件兼容性解决方案#
兼容性处理的原则: 首先照顾大多数浏览器,再处理特殊浏览器
/*
参数说明
element:元素对象
eventName:事件类型
fn:监听器
*/
function addEventListener(element, eventName, fn) {
// 判断当前浏览器是否支持 addEventListener 方法,若不支持返回 undefined
if (element.addEventListener) {
element.addEventListener(eventName, fn); // 第三个参数 默认是false
} else if (element.attachEvent) {
element.attachEvent('on' + eventName, fn);
} else {
// 相当于 element.onclick = fn;
element['on' + eventName] = fn;
}
}
⑤ 删除事件(解绑事件)
1. 传统注册方式解绑#
//eventTarget:绑定事件的元素对象
eventTarget.onclick = null;
2. 方法监听注册方式解绑#
//解除addEventListener绑定的事件
eventTarget.removeEventListener(type, listener, useCapture);
//解除attachEvent绑定的事件
eventTarget.detachEvent(eventNameWithOn, callback);
3. 删除事件兼容性解决方案#
function removeEventListener(element, eventName, fn) {
// 判断当前浏览器是否支持 removeEventListener 方法
if (element.removeEventListener) {
element.removeEventListener(eventName, fn); // 第三个参数 默认是false
} else if (element.detachEvent) {
element.detachEvent('on' + eventName, fn);
} else {
element['on' + eventName] = null;
}
}
⑥ DOM事件流
事件流描述的是从页面中接收事件的顺序。
事件发生时会在元素节点之间按照特定的顺序传播, 这个传播过程即 DOM 事件流。
DOM 事件流分为3个阶段:
- 捕获阶段
- 当前目标阶段
- 冒泡阶段
比如:我们给页面中的一个div注册了单击事件,当你单击了div时,也就单击了body,单击了html,单击了document。
- 事件冒泡: IE 最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点的过程。
- 事件捕获: 网景最早提出, 由 DOM 最顶层节点开始,然后逐级向下传播到到最具体的元素接收的过程。
注意
- JS 代码中事件的注册只能在捕获或者冒泡其中的一个阶段,但浏览器全过程事件流依然执行。
onclick
和attachEvent
只能得到冒泡阶段。addEventListener(type, listener, useCapture)
第三个参数如果是 true,表示在事件捕获阶段调用事件处理程序;如果是 false(不写默认就是false),表示在事件冒泡阶段调用事件处理程序。- 实际开发中我们很少使用事件捕获,我们更关注事件冒泡。
- 有些事件是没有冒泡的,比如
onblur、 onfocus、 onmouseenter、 onmouseleave
⑦ 事件对象
1. 简介#
eventTarget.onclick = function(event) {}
eventTarget.addEventListener('click', function(event){})
// 这个 event 就是事件对象,我们还喜欢的写成 e 或者 evt
event
对象代表事件的状态, 比如键盘按键的状态、鼠标的位置、鼠标按钮的状态
事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象。
2. 事件对象的使用#
eventTarget.onclick = function(event) {
// 这个 event 就是事件对象,我们还喜欢的写成 e 或者 evt
}
eventTarget.addEventListener('click', function(event) {
// 这个 event 就是事件对象,我们还喜欢的写成 e 或者 evt
})
这个 event
是个形参,系统帮我们设定为事件对象,不需要传递实参过去。
当我们注册事件时, event 对象就会根据事件类型被系统自动创建, 并依次传递给事件监听器(事件处理函数) 。
3. 事件对象的兼容性方案#
事件对象本身的获取存在兼容问题:
- 标准浏览器中是浏览器给方法传递的参数, 只需要定义形参 e 就可以获取到。
- 在 IE6~8 中,浏览器不会给方法传递参数,如果需要的话, 需要到 window.event 中获取查找。
解决:
e = e || window.event;
4. 事件对象的常见属性和方法#
事件对象属性方法 | 说明 |
---|---|
e.target |
返回触发事件的对象(标准) |
e.srcElement |
返回触发事件的对象(非标准,ie6~8使用) |
e.type |
返回事件类型,比如 click(不带on), mouseover |
e.returnValue |
该属性阻止默认事件(默认行为,非标准,ie6~8使用,比如不让链接跳转) |
e.preventDefault() |
该方法阻止默认事件(默认行为,标准) |
e.stopPropagation() |
阻止冒泡(标准) |
e.cancelBubble |
该属性阻止冒泡(非标准,ie6~8使用) |
this 、 e.currentTarget \ e.target 、e.srcElement 的区别#
-
this、e.currentTarget
是事件绑定的元素, 这个函数的调用者(绑定这个事件的元素)-
兼容性问题:
this兼容性较好,推荐使用
e.currentTarget
针对IE9之前
-
-
e.target 、e.srcElement
是事件触发的元素。-
兼容性问题:
e.target
高版本浏览器支持e.srcElement
针对IE9之前 -
解决方案
e = e || window.event; var target = e.target || e.srcElement;
-
阻止默认事件#
元素对象默认事件?
阻止默认事件的三种方法
-
e.preventDefault()
有兼容性问题,高版本适配
-
e.returnValue
有兼容性问题,低版本适配
-
return false
没兼容性问题,但其后的语句不会执行
实例
<body>
<a href="www.baidu.com">百度</a>
</body>
<script>
var a = document.querySelector('a');
a.onclick = function(e) {
//阻止链接默认的跳转事件
//方式一
if(e){
e.preventDefault();
}else{
e = window.event;
e.returnValue;
}
//方式二
//return false;
}
</script>
阻止事件冒泡#
-
标准写法:利用事件对象里面的
stopPropagation()
方法e.stopPropagation()
-
非标准写法: IE 6-8 利用事件对象 cancelBubble 属性
e.cancelBubble = true;
-
阻止事件冒泡的兼容性解决方案
if(e && e.stopPropagation){ e.stopPropagation(); }else{ window.event.cancelBubble = true; }
鼠标事件对象常见属性#
鼠标事件的类型很多,但它们的事件对象都是MouseEvent
常见属性
属性 | 说明 |
---|---|
e.clientX |
返回鼠标相对于浏览器窗口可视区域的 X 坐标 |
e.clientY |
返回鼠标相对于浏览器窗口可视区域的 Y 坐标 |
e.pageX |
返回鼠标相对于文档页面的 X 坐标 IE9+支持 |
e.pageY |
返回鼠标相对于文档页面的 Y 坐标 IE9+支持 |
e.screenX |
返回鼠标相对于电脑屏幕的 X 坐标 |
e.screenY |
返回鼠标相对于电脑屏幕的 Y 坐标 |
键盘事件对象常见属性#
键盘事件对象 | 说明 |
---|---|
e.keyCode |
返回改键的ASCII值 |
e.key |
返回按下的键名 |
- key有严重的兼容性问题,不推荐使用
- keyup 、keydown 事件不区分字母大小写 a 和 A 得到的keyCode值都是65,keypress 事件 区分字母大小写 a 97 和 A 得到的是65
触摸事件对象#
TouchEvent
是一类描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件对象。这类事件对象用于描述一个或多个触点,使开发者可以检测触点的移动,触点的增加和减少,等等。
类型 | 何时触发 |
---|---|
touchstart | 触摸元素时触发 |
touchmove | 移动触点时触发 |
touchend | 触点消失时触发 |
每个触摸事件都会各自有事件对象。
element.addEventListener('touchstart',function() {
console.log(e);
})
常见的触摸事件对象属性:
属性 | 说明 |
---|---|
e.touches | 正在触摸屏幕的所有触点的一个列表 |
e.targetTouches | 正在触摸当前DOM元素上的触点的一个列表 |
e.changedTouches | 触点状态发生了改变的列表,从无到有,从有到无变化 |
e.preventDefault() | 该方法阻止默认事件,比如:手指移动也会触发滚动屏幕所以这里要阻止默认的屏幕滚动 |
这三属性都返回一个TouchList对向,记录触点和触点的数量
一般都是给元素注册触摸事件,所以重点记住 targetTocuhes
targetTouches['0']//返回第一个触点对象Touch
案例:
var div = document.querySelector('div');
div.addEventListener('touchstart', function(e) {
console.log(e.touches);
console.log(e.targetTouches);
console.log(e.changedTouches);
})
div.addEventListener('touchmove', function(e) {
console.log(e.touches);
console.log(e.targetTouches);
console.log(e.changedTouches);
})
div.addEventListener('touchend', function(e) {
console.log(e.touches);
console.log(e.targetTouches);
console.log(e.changedTouches);
})
上述事件分别以一触点触发一次,输出如下结果
5. 事件委托(代理,委派)#
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script>
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
alert('hello');
var list = ul.children;
for (var i = 0; i < list.length; i++) {
list[i].style.backgroundColor = '';
}
e.target.style.backgroundColor = 'pink';
})
</script>
</body>
事件委托也称为事件代理, 在 jQuery 里面称为事件委派。
原理:不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
作用:只操作了一次 DOM ,提高了程序的性能
作者:Hong•Guo
出处:https://www.cnblogs.com/ghnb1/p/15846679.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix