事件高级
1. 注册事件(绑定事件)
给元素添加事件,称为注册事件(绑定事件)
注册事件有两种方式:
- 传统方式
利用on开头的事件onclick , 利用事件三要素 来注册
特点:
注册事件的唯一性:
就是同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数会覆盖前面的注册的处理函数 - 方法监听注册方式
是W3C标准,也是推荐方式
用到 addEventListener() 方法 ,IE9以上版本支持
特点:
同一个元素同一个事件可以注册多个处理监听器,会按照注册顺序依次执行
监听器就是监听处理函数
eventTarget.addEventListener(‘type’, listener, useCapture)
方法实现将指定的监听器注册到eventTarget(目标对象)上,当 该对象触发指定的事件时,就会执行事件处理函数
该方法接收三个参数:
- type: 事件类型字符串,比如 click , mouseover, 这里不带 on
- listener: 事件处理函数 ,事件发生时,会调用该监听函数
- useCapture: 可选参数, 是一个布尔值, 默认是false
<body>
<button>传统方式</button>
<button>方法监听注册方式</button>
<script>
var btns = document.querySelectorAll("button");
//1. 给第一个按钮以传统方式注册同一个事件“弹出一个对话框”
btns[0].onclick = function(){
alert('hi');
}
btns[0].onclick = function(){
alert('nihao');
}
//结果只有第二个事件触发
//2.给第二个按钮以方法监听方式注册同一个事件“弹出一个对话框”
btns[1].addEventListener('click',function(){
alert('hi');
})
//addEventListener 方法里面的事件类型是字符串,必须加引号,并且不带 on
btns[1].addEventListener('click',function(){
alert('22');
})
</script>
</body>
2. 删除事件(解绑事件)
- 传统方式:
eventTarget.onclick = null; - eventTarget.removeEventListener(‘type’, listener, useCapture)
因为移除时要将那个函数移除要写出来,不可以用匿名函数的形式
就是添加注册事件 另写一个函数
<body>
<button>传统方式注册和删除事件</button>
<button>方法监听注册和删除事件</button>
<script>
var btns = document.querySelectorAll("button");
//1. 给第一个按钮以传统方式注册同一个事件“弹出一个对话框”
btns[0].onclick = function(){
alert('hi');
btns[0].onclick = null;//解绑
}
//2.给第二个按钮以方法监听方式注册同一个事件“弹出一个对话框”
// btns[1].addEventListener('click',function(){
// alert('hi');
// })
btns[1].addEventListener('click',fn);//此处函数调用没有小括号,
function fn(){
alert('hi');
//解绑
btns[1].removeEventListener('click',fn);
}
</script>
</body>
DOM事件流: 事件的传播过程
- 事件流描述的是从页面中接收事件的顺序
- 事件发生时会在元素节点之间按照特定的顺序传播,这个传播的过程就是DOM事件流
- DOM事件流分为3个阶段:
(1)捕获阶段
(2)当前目标阶段
(3)冒泡阶段
例如:我们给一个div注册了点击事件:
先从Document节点先接收到点击事件,因为没有做处理程序,不会执行任何操作
向下传播,到Element html 节点,执行以上操作,再往下传播,到Element body 节点,再到Element div 节点 , 其中的节点都会接收到此点击事件,若有具体的事件处理程序就执行,没有就往下依次传播,以上阶段称为捕获阶段
div去执行,称为当前目标阶段
div执行完,会传播到Element body 节点,接收到了此点击事件,没有任何操作,再往上依次传播到Document节点,以上阶段称为冒泡阶段
捕获阶段:由DOM最顶层节点开始,然后逐级向下传播到最具体的元素接收的过程
冒泡阶段:事件由最具体的元素接收,逐级向上传播到DOM最顶层节点的过程
- JS代码只能执行捕获或者冒泡中的一个阶段,onclick只能得到冒泡阶段,对于addEventListener(‘type’, listener, useCapture) 的第三个参数若是true,表示事件捕获阶段调用事件处理程序,第三个参数若是false,表示事件冒泡阶段调用事件处理程序。
- 有些事件没有冒泡的:onbur , onfocus, onmouseenter, onmouseleave
<body>
<div class="father">
<div class="son">儿子</div>
</div>
<script>
// 最里层的div
var son = document.querySelector('.son');
son.addEventListener('click',function(e){
alert('son');
},false);
// father层的div
var father = document.querySelector('.father');
father.addEventListener('click',function(e){
alert('father');
},false);
// 最高级的大盒子
document.addEventListener('click',function(e){
alert('document');
},false);
// 对于以上代码:(体会冒泡阶段)
// 点击儿子盒子,会依次弹出 son father document
// 点击父亲盒子,会依次弹出 father document
// 点击document盒子,会依次弹出 document
</script>
</body>
事件对象
事件对象代表事件的状态,比如键盘按键的状态,鼠标的位置;
事件发生后,跟事件相关的信息数据的集合都放到这个对象里
- 事件对象写到监听函数的小括号里面的,当形参来看
- 事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
- 事件对象是事件一系列相关数据的集合,和事件相关的,比如鼠标点击里面就包含了鼠标的相关信息,比如鼠标坐标,若是键盘事件,里面就包含了键盘事件的信息,按的是哪一个键等
- 事件对象是自定义来命名的,常常写event , evt 和e
- 事件对象有兼容性问题(了解),就是旧版本的 IE,会识别 window.event
<button>方式</button>
<script>
// eventTarget.onclick = function(event){}
// eventTarget.addEventListener('click',function(event){})
var btns = document.querySelector("button");
// btns.onclick = function(e){
// console.log(e);
// }
btns.addEventListener('click',function(e){
console.log(e);
})
</script>
</body>
1. 事件对象的常见的属性和方法
1. e.target 返回触发的对象
区别于this:
e.target 点击了那个元素,就返回那个元素
this 那个元素绑定了这个点击事件,就返回那个元素
<body>
<div>123</div>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<!-- 给div注册点击事件 -->
<script>
// 1.e.target 返回触发的对象(元素)
var div = document.querySelector('div');
div.addEventListener('click',function(e){
console.log(e.target);
//效果就是当点击时,控制台输出<div>123</div>
console.log(this);
//此时的this效果和target相同
})
// this 返回的是绑定事件的对象(元素)
// 重点:区分二者
var ul = document.querySelector('ul');
ul.addEventListener('click',function(e){
//因为给ul绑定了事件 ,所以this 就指向了ul
console.log(this);
//e.target 指向我们点击的那个对象,就是谁触发了这个事件,
//我们点击li ,因为有冒泡,也会触发这个点击,所以e.target指向li
console.log(e.target);
})
</script>
2. e.type 返回事件的类型 比如:click mouseover 不带on
<body>
<div>123</div>
<script>
var div = document.querySelector('div');
div.addEventListener('click',fn);
function fn(e){
console.log(e.type);//click
}
</script>
</body>
3. e.preventDefault() 阻止默认的事件(行为)
<body>
<a href="http://www.baidu.com">百度</a>
<button>提交</button>
<script>
// 阻止默认的事件(行为) :为了让链接不跳转,或者提交按钮不提交
var a = document.querySelector('a');
a.addEventListener('click',fn);
function fn(e){
e.preventDefault();
}
var btn = document.querySelector('button');
btn.addEventListener('click',fn);
function fn(e){
e.preventDefault();
}
</script>
</body>
4. e.stopPropagation() 阻止事件冒泡阶段
<body>
<div class="father">
<div class="son">儿子</div>
</div>
<script>
// 最里层的div
var son = document.querySelector('.son');
son.addEventListener('click',function(e){
alert('son');
e.stopPropagation();//添加后只弹出son 不再向上冒泡
},false);
// father层的div
var father = document.querySelector('.father');
father.addEventListener('click',function(e){
alert('father');
},false);
// 最高级的大盒子
document.addEventListener('click',function(e){
alert('document');
},false);
</script>
2. 利用事件冒泡阶段:事件委托:不是每个子节点单独添加事件监听器,而是将其设置在其父节点上,然后利用冒泡原理影响设置每个子节点(利用事件对象的target获得触发事件对象的子节点,事件冒泡到已经绑定了事件的父节点上,就可以触发事件了)
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<!-- 要给每个li添加点击事件 -->
<script>
// 给ul注册点击事件,利用事件对象的target找到当前点击的li,因为点击li,事件会冒泡到ul上
// ul有注册点击事件,就会 触发事件监听器
var ul = document.querySelector('ul');
ul.addEventListener('click',function(e){
// alert('加油,坚持,耐心');
// 若想点击li时,改变该li的背景色:那需要获取到 触发事件的对象 e.target
e.target.style.backgroundColor = 'pink';
})
</script>
</body>
3.常用的鼠标事件
之前学过:onclick onmouseover onmouseout onfocus onblur
<body>
<div>不想被复制的文字</div>
<!-- (了解) -->
<script>
// 1.禁止鼠标右键菜单
// contexmenu 控制何时显示上下菜单
document.addEventListener('contextmenu',function(e){
e.preventDefault();
})//效果是鼠标右击失效
//2.禁止鼠标选中
// selectstart 开始选中
document.addEventListener('selectstart',function(e){
e.preventDefault();
})//效果是鼠标选中失效
</script>
</body>
4.鼠标事件对象 MouseEvent
- e.clientX 返回鼠标相对于浏览器窗口可视区的x的坐标,(距离可视区左沿的距离)
- e.clientY 返回鼠标相对于浏览器窗口可视区的y的坐标,(距离可视区上沿的距离)
当文档比较长时,就是比可视区长:
3. e.pageX 返回鼠标相对于文档页面的x的坐标
4. e.pageY 返回鼠标相对于文档页面的y的坐标
跟随鼠标的图片:(思路要知道)
- 鼠标不断移动,使用鼠标移动事件:mousemove
- 在页面中移动,给document注册事件
- 图片要移动距离,而且不占位置,使用绝对定位
- 核心:每次鼠标移动,都会获得最新的鼠标坐标,将x和y坐标作为图片的top和left的值就可以实现移动图片
<style>
img{
position:absolute;
}
</style>
</head>
<body>
<img src="imagines/logo02.jpg" alt="">;
<script>
var img = document.querySelector('img');
document.addEventListener('mousemove',function(e){
var x = e.pageX;
var y = e.pageY;
//对于加了定位的,就是position,一定要给个类似于top等的带有px单位的数值
// img.style.left=x +'px';
// img.style.top = y+'px';
// 实现鼠标在图片的中间,将位置往上走图片高度一半,是负的
img.style.left=x -50+'px';
img.style.top = y-50+'px';
})
</script>
</body>
5.常用的键盘事件
- onkeyup 某个键盘按键被松开时触发
- onkeydown 某个键盘按键被按下时触发
- onkeypress 某个键盘按键被按下时触发,但它不识别功能键,例如:ctrl shift 箭头等等
三个事件执行顺序:keydown keypress keyup
<script>
// 利用事件监听器,不加on
document.addEventListener('keyup', function () {
console.log('按键弹起触发up');
})
document.addEventListener('keydown', function () {
console.log('按键按下触发 down');
})
document.addEventListener('keypress', function () {
console.log('按键按下触发 press');
})
</script>
6.键盘事件对象 KeyboardEvent
键盘事件对象keyCode 属性,返回该键的ASCII码值
<script>
// 利用键盘事件对象keyCode 属性,判断用户按下哪个键
document.addEventListener('keyup', function (e) {
console.log(e.keyCode);
if(e.keyCode==65){
alert('你按下的是a键');
}
})
document.addEventListener('keypress', function (e) {
console.log(e.keyCode);
})
//效果就是:按下 a, 输出 97和65
// 1.keyup 和 keydown 事件不区分字母大小写 a和A得到的都是65
// 2.keypress 事件区分字母大小写 a得到的是97,A得到的是65
</script>
模拟京东按键输入内容案例
京东网页中,按下键盘的s键,就可以自动将光标定到搜索框,方便用户输入内容
分析:
- 检测用户是否按下s键,若按下s键,就将光标定位到搜索框里面
- 用键盘事件对象keyCode 属性,判断用户按下是否为s键
- 搜索框获得焦点,使用js里面的 focus() 方法
<body>
<input type="text" name="" id="">
<script>
var search = document.querySelector('input');
document.addEventListener('keyup', function (e) {
// console.log(e.keyCode);//先自己手动得到s键对应的ASCII码值是83
if (e.keyCode == 83) {
search.focus();
}
})
//是keyup 这样触发事件时,才不会将s写进去
</script>
</body>
模拟京东快递单号查询案例
就是输入单号时,在上面多出一个框,里面不仅会显示单号的内容,同时单号的字号大一些,看的更清楚
分析:
- 快递单号输入内容时,上面的大号字体盒子显示
- 表单检测用户输入:给表单添加键盘事件
- 把快递单号里面的值value获取过来赋值给大盒子(innerText)作为内容
- 若快递单号里面的值为空,则隐藏上面的大号字体盒子
<style>
.search{
height: 300px;
width: 300px;
margin:auto;
background-color: pink;
position: relative;
}
.con {
display: none;
/* position:absolute; */
height: 200px;
/* top: 150px;
left:50px; */
background-color: red;
font-size: large;
font-weight: 900;
color: blue;
}
.jg{
position:absolute;
height: 50px;
color:#333;
top: 220px;
left:50px;
}
</style>
</head>
<body>
<div class="search">
<div class="con"></div>
<input type="text" placeholder="请输入你的快递单号" class="jg">
</div>
<script>
var con = document.querySelector('.con');
var jg = document.querySelector('.jg');
//表单检测用户输入:给表单添加键盘事件
jg.addEventListener('keyup', function () {
if (this.value == '') {
con.style.display = 'none';
}
else {
con.style.display = 'block';
con.innerHTML = this.value;
}
})
//keydown 和 keypress 在文本框里面的特点:连个事件触发时,文字还没有落入文本框
//keyup 事件触发时,文字已经落入文本框了
//当失去焦点就隐藏这个con盒子
jg.addEventListener('blur',function(){
con.style.display = 'none';
})
//当获得焦点就显示这个con盒子
jg.addEventListener('focus',function(){
if(this.value){
con.style.display = 'block';
}
})
</script>
</body>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现