dom中的事件处理

news/2025/2/13 21:24:03/

事件参考 | MDN (mozilla.org)

什么是事件 

 事件监听方式

直接在html中编写JavaScript代码(了解)

  <button οnclick="console.log('按钮1发生了点击~');">按钮1</button>

DOM属性,通过元素的on.....来监听事件

// 2.onclick属性// function handleClick01() {//   console.log("按钮2发生了点击~")// }// function handleClick02() {//   console.log("按钮2的第二个处理函数")// }// btn2El.onclick = handleClick01// btn2El.onclick = handleClick02

缺陷: 

但是如果同一个交互这么执行多个操作,最后面的操作会覆盖前面的,只会有一个被执行

addEventListener(推荐)

    btn3El.addEventListener("click", function() {console.log("第一个btn3的事件监听~")})btn3El.addEventListener("click", function() {console.log("第二个btn3的事件监听~")})btn3El.addEventListener("click", function() {console.log("第三个btn3的事件监听~")})

这样可以同时执行三个操作,更为灵活

常见的事件列表

◼ 鼠标事件:
 click —— 当鼠标点击一个元素时(触摸屏设备会在点击时生成)。
 mouseover / mouseout —— 当鼠标指针移入/离开一个元素时。
 mousedown / mouseup —— 当在元素上按下/释放鼠标按钮时。
 mousemove —— 当鼠标移动时。
◼ 键盘事件:
 keydown 和 keyup —— 当按下和松开一个按键时。
◼ 表单(form)元素事件:
 submit —— 当访问者提交了一个 <form> 时。
 focus —— 当访问者聚焦于一个元素时,例如聚焦于一个 <input>。
◼ Document 事件:
 DOMContentLoaded —— 当 HTML 的加载和处理均完成,DOM 被完全构建完成时。
◼ CSS 事件:
 transitionend —— 当一个 CSS 动画完成时。

认识事件流


◼ 事实上对于事件有一个概念叫做事件流,为什么会产生事件流呢?
 我们可以想到一个问题:当我们在浏览器上对着一个元素点击时,你点击的不仅仅是这个元素本身;
这是因为我们的HTML元素是存在父子元素叠加层级的;
 比如一个span元素是放在div元素上的,div元素是放在body元素上的,body元素是放在html元素上的;
 

事件冒泡与事件捕获

◼ 我们会发现默认情况下事件是从最内层的span向外依次传递的顺序,这个顺序我们称之为事件冒泡(Event Bubble);
◼ 事实上,还有另外一种监听事件流的方式就是从外层到内层(body -> span),这种称之为事件捕获(Event Capture);←添加true即变为事件捕获

 // 默认情况下是事件冒泡spanEl.addEventListener("click", function() {console.log("span元素发生了点击~冒泡")})divEl.addEventListener("click", function() {console.log("div元素发生了点击~冒泡")})bodyEl.addEventListener("click", function() {console.log("body元素发生了点击~冒泡")})// 设置希望监听事件捕获的过程spanEl.addEventListener("click", function() {console.log("span元素发生了点击~捕获")}, true)divEl.addEventListener("click", function() {console.log("div元素发生了点击~捕获")}, true)bodyEl.addEventListener("click", function() {console.log("body元素发生了点击~捕获")}, true)


◼ 为什么会产生两种不同的处理流呢?
 这是因为早期浏览器开发时,不管是IE还是Netscape公司都发现了这个问题;
 但是他们采用了完全相反的事件流来对事件进行了传递;
 IE采用了事件冒泡的方式,Netscape采用了事件捕获的方式;


◼ 如果我们都监听,那么会按照如下顺序来执行:(先捕获再冒泡,两个过程都是完整的,这一系列是一个过程,如果某一步被阻止,后续都被阻止)
◼ 捕获阶段(Capturing phase):
         事件(从 Window)向下走近元素。
◼ 目标阶段(Target phase):
         事件到达目标元素。
◼ 冒泡阶段(Bubbling phase):
         事件从元素上开始冒泡。


◼ 事实上,我们可以通过event对象来获取当前的阶段:
         eventPhase


◼ 开发中通常会使用事件冒泡,所以事件捕获了解即可。

事件对象

◼ 当一个事件发生时,就会有和这个事件相关的很多信息:
         比如事件的类型是什么,你点击的是哪一个元素,点击的位置是哪里等等相关的信息;
         那么这些信息会被封装到一个Event对象中,这个对象由浏览器创建,称之为event对象;
         该对象给我们提供了想要的一些属性,以及可以通过该对象进行某些操作;
◼ 如何获取这个event对象呢?
         event对象会在传入的事件处理(event handler)函数回调时,被系统传入;
         我们可以在回调函数中拿到这个event对象;

 event常见的属性与方法

◼ 常见的属性:
 type:事件的类型;←比如click
 target:当前事件发生的元素;
 currentTarget:当前处理事件的元素;
 eventPhase:事件所处的阶段;←是事件捕获的阶段
 offsetX、offsetY:事件发生在元素内的位置;
 clientX、clientY:事件发生在客户端内的位置;
 pageX、pageY:事件发生在客户端相对于document的位置;
 screenX、screenY:事件发生相对于屏幕的位置;

    divEl.onclick = function(event) {// 1.偶尔会使用console.log("事件类型:", event.type)console.log("事件阶段:", event.eventPhase)// 2.比较少使用console.log("事件元素中位置", event.offsetX, event.offsetY)console.log("事件客户端中位置", event.clientX, event.clientY)console.log("事件页面中位置", event.pageX, event.pageY)console.log("事件在屏幕中位置", event.screenX, event.screenY)}

如果事件发生的位置就是监听的位置,target/currentTarget无区别,甚至===

但是如果是:事件发生的位置不是监听的位置,事件发生的位置是通过冒泡事件传递到的监听位置,此时target/currentTarget有区别

target永远是事件发生的对象,currentTarget是当前处理的对象,即正在监听的对象

// 3.target/currentTargetconsole.log(event.target)console.log(event.currentTarget)console.log(event.currentTarget === event.target)

◼ 常见的方法:
 preventDefault:取消事件的默认行为;←比如阻止a元素的点击自动跳转链接
 stopPropagation:阻止事件的进一步传递(冒泡或者捕获都可以阻止)

    // 1.阻止默认行为// var aEl = document.querySelector("a")// aEl.onclick = function(event) {//   console.log("a元素发生了点击~")//   event.preventDefault()// }

先捕获再冒泡,两个过程都是完整的,这一系列是一个过程,如果某一步被阻止,后续都被阻止

    divEl.addEventListener("click", function(event) {console.log("div的事件捕获监听~")// event.stopPropagation()}, true)spanEl.addEventListener("click", function() {console.log("span的事件捕获监听~")}, true)btnEl.addEventListener("click", function(event) {console.log("button的事件捕获监听~")// event.stopPropagation()}, true)divEl.addEventListener("click", function() {console.log("div的事件冒泡监听~")})spanEl.addEventListener("click", function(event) {console.log("span的事件冒泡监听~")event.stopPropagation()})btnEl.addEventListener("click", function() {console.log("button的事件冒泡监听~")})

事件处理中的this

在函数中,我们也可以通过this来获取当前处理的对象,即正在监听的对象
◼ 这是因为在浏览器内部,调用event handler是绑定到当前的Currenttarget上的

EventTarget类及常见方法

我们会发现,所有的节点、元素都继承自EventTarget
 事实上Window也继承自EventTarget;
◼ 那么这个EventTarget是什么呢?
 EventTarget是一个DOM接口,主要用于添加、删除、派发Event事件;
◼ EventTarget常见的方法:
 addEventListener:注册某个事件类型以及事件处理函数;
 removeEventListener:移除某个事件类型以及事件处理函数;
 dispatchEvent:派发某个事件类型到EventTarget上;

// 1.将监听函数移除的过程// var foo = function() {//   console.log("监听到按钮的点击")// }// btnEl.addEventListener("click", foo)// // 需求: 过5s钟后, 将这个事件监听移除掉// setTimeout(function() {//   btnEl.removeEventListener("click", foo)// }, 5000)// 这种做法是无法移除的btnEl.addEventListener("click", function() {console.log("btn监听的处理函数~")})setTimeout(function() {btnEl.removeEventListener("click", function() {})}, 5000)

因为remove的function不明 

    // eventtarget就可以实现类似于事件总线的效果window.addEventListener("coderwhy", function() {console.log("监听到coderwhy的呼唤~")})setTimeout(function() {window.dispatchEvent(new Event("coderwhy"))}, 5000)

事件委托/代理 

◼ 事件冒泡在某种情况下可以帮助我们实现强大的事件处理模式 – 事件委托模式(也是一种设计模式)
◼ 那么这个模式是怎么样的呢?
         因为当子元素被点击时,父元素可以通过冒泡可以监听到子元素的点击,并且可以通过event.target获取到当前监听的元素;
◼ 案例:一个ul中存放多个li,点击某一个li会变成红色
         方案一:监听每一个li的点击,并且做出相应;
         方案二:在ul中监听点击,并且通过event.target拿到对应的li进行处理;
✓ 因为这种方案并不需要遍历后给每一个li上添加事件监听,所以它更加高效;

案例:一个ul中存放多个li,点击某一个li会变成红色

   // 1.每一个li都监听自己的点击, 并且有自己的处理函数(自己的函数)// var liEls = document.querySelectorAll("li")// for (var liEl of liEls) {//   // 监听点击//   liEl.onclick = function(event) {//此处也可写为this.classList.add("active")//错误写法是liEl.classList.add("active"),因为这样for循环只会实现最后一个//     event.currentTarget.classList.add("active")//   }// }

target永远是事件发生的对象,currentTarget是当前处理的对象,即正在监听的对象

    // 2.统一在ul中监听// var ulEl = document.querySelector("ul")// ulEl.onclick = function(event) {//   console.log("点击了某一个li", event.target)//   event.target.classList.add("active")// }
// 3.新需求: 点击li变成active, 其他的取消activevar ulEl = document.querySelector("ul")var activeLiEl = nullulEl.onclick = function(event) {// 1.将之前的active移除掉// for (var i = 0; i < ulEl.children.length; i++) {//   var liEl = ulEl.children[i]//   if (liEl.classList.contains("active")) {//     liEl.classList.remove("active")//   }// }// 1.找到active的li, 移除掉active// var activeLiEl = ulEl.querySelector(".active")// if (activeLiEl) {//   activeLiEl.classList.remove("active")// }// 1.变量记录的方式// edge caseif (activeLiEl) {activeLiEl.classList.remove("active")}// 2.给点击的元素添加activeevent.target.classList.add("active")// 3.记录最新的active对应的liactiveLiEl = event.target}

案例2 

  <div class="box"><button data-action="search">搜索~</button><button data-action="new">新建~</button><button data-action="remove">移除~</button><button>1111</button></div><script>var boxEl = document.querySelector(".box")boxEl.onclick = function(event) {var btnEl = event.targetvar action = btnEl.dataset.actionswitch (action) {case "remove":console.log("点击了移除按钮")breakcase "new":console.log("点击了新建按钮")breakcase "search":console.log("点击了搜索按钮")breakdefault:console.log("点击了其他")}}</script>

 常见的鼠标事件

 <div class="box"></div><script>// 鼠标事件var boxEl = document.querySelector(".box")boxEl.onclick = function() {console.log("click")}boxEl.oncontextmenu = function(event) {console.log("点击了右键")event.preventDefault()}// 变量记录鼠标是否是点下去的var isDown = falseboxEl.onmousedown = function() {console.log("鼠标按下去")isDown = true}boxEl.onmouseup = function() {console.log("鼠标抬起来")isDown = false}boxEl.onmousemove = function() {if (isDown) {console.log("鼠标在div上面移动")}}</script>

 mouseover与mouserenter的区别

 不支持冒泡意思是只进行这一步


◼ mouseenter和mouseleave
         不支持冒泡
         进入子元素依然属于在该元素内,没有任何反应
◼ mouseover和mouseout
         支持冒泡
         进入元素的子元素时
        ✓ 先调用父元素的mouseout
        ✓ 再调用子元素的mouseover
        ✓ 因为支持冒泡,所以会将mouseover传递到父元素中;

   <div class="box"><span></span></div><script>var boxEl = document.querySelector(".box")var spanEl = document.querySelector("span")// 1.第一组boxEl.onmouseenter = function() {console.log("box onmouseenter")}boxEl.onmouseleave = function() {console.log("box onmouseleave")}spanEl.onmouseenter = function() {console.log("span onmouseenter")}spanEl.onmouseleave = function() {console.log("span onmouseleave")}// 第二组// boxEl.onmouseover = function() {//   console.log("box onmouseover")// }// boxEl.onmouseout = function() {//   console.log("box onmouseout")// }</script>

  mouseover与mouserenter区别的应用

  <div class="box"><button>删除</button><button>新增</button><button>搜索</button></div><script>// 方案一: 监听的本身就是button元素// var btnEls = document.querySelectorAll("button")// for (var i = 0; i < btnEls.length; i++) {//   btnEls[i].onmouseover = function(event) {//     console.log(event.target.textContent)//   }// }// 方案二: 事件委托var boxEl = document.querySelector(".box")boxEl.onmouseover = function(event) {console.log(event.target.textContent)}

enter/leave不能作事件委托,但是over/out可以

over使用更多

常见的键盘事件

 ◼ 事件的执行顺序是 onkeydown、onkeypress、onkeyup
 down事件先发生;
 press发生在文本被输入;
 up发生在文本输入完成;
◼ 我们可以通过key和code来区分按下的键:
 code:“按键代码”("KeyA","ArrowLeft" 等),特定于键盘上按键的物理位置。
 key:字符("A","a" 等),对于非字符(non-character)的按键,通常具有与 code 相同的值。)

  <input type="text"><button>搜索</button><script>var inputEl = document.querySelector("input")var btnEl = document.querySelector("button")// inputEl.onkeydown = function() {//   console.log("onkeydown")// }// inputEl.onkeypress = function() {//   console.log("onkeypress")// }// inputEl.onkeyup = function(event) {//   console.log(event.key, event.code)// }// 1.搜索功能btnEl.onclick = function() {console.log("进行搜索功能", inputEl.value)}inputEl.onkeyup = function(event) {if (event.code === "Enter") {console.log("进行搜索功能", inputEl.value)}}// 2.按下s的时候, 搜索自动获取焦点document.onkeyup = function(event) {if (event.code === "KeyD") {inputEl.focus()}}</script>

常见的表单事件

  <form action="/abc"><input type="text"><textarea name="" id="" cols="30" rows="10"></textarea><button type="reset">重置</button><button type="submit">提交</button></form><script>var inputEl = document.querySelector("input")// 1.获取焦点和失去焦点inputEl.onfocus = function() {console.log("input获取到了焦点")}inputEl.onblur = function() {console.log("input失去到了焦点")}// 2.内容发生改变/输入内容// 输入的过程: input// 内容确定发生改变(离开): change失去焦点inputEl.oninput = function() {console.log("input事件正在输入内容", inputEl.value)}inputEl.onchange = function() {console.log("change事件内容发生改变", inputEl.value)}// 3.监听重置和提交var formEl = document.querySelector("form")formEl.onreset = function(event) {console.log("发生了重置事件")event.preventDefault()}formEl.onsubmit = function(event) {console.log("发生了提交事件")// axios库提交event.preventDefault()}</script>

文档加载事件


◼ DOMContentLoaded:浏览器已完全加载 HTML,并构建了 DOM 树,但像 <img> 和样式表之类的外部资源可能尚未加载完成。比如无法拿到图片占据的空间,为0如果拿到了,说明是缓存。
◼ load:浏览器不仅加载完成了 HTML,还加载完成了所有外部资源:图片,样式等。

  <script>// 注册事件监听window.addEventListener("DOMContentLoaded", function() {// 1.这里可以操作box, box已经加载完毕// var boxEl = document.querySelector(".box")// boxEl.style.backgroundColor = "orange"// console.log("HTML内容加载完毕")// 2.获取img对应的图片的宽度和高度var imgEl = document.querySelector("img")console.log("图片的宽度和高度:", imgEl.offsetWidth, imgEl.offsetHeight)})window.onload = function() {console.log("文档中所有资源都加载完毕")// var imgEl = document.querySelector("img")// console.log("图片的宽度和高度:", imgEl.offsetWidth, imgEl.offsetHeight)}window.onresize = function() {console.log("创建大小发生改变时")}</script><div class="box"><p>哈哈哈啊</p></div><a href="#">百度一下</a><img src="../images/kobe01.jpg" alt="">


http://www.ppmy.cn/news/96679.html

相关文章

android 12.0Launcher3长按拖拽时最后一屏未满时不让拖拽到后一屏(二)

1.概述 在12.0定制化开发中,如果专门适配老年机的时候,这时客户提出要求,如果最后一屏未满时,不让拖拽到后面一屏的空屏中,等当前屏填满了以后,才能拖到下一屏的功能,所以要从workspace的拖拽类开始着手分析 2.长按拖拽时最后一屏未满时不让拖拽到后一屏(二)核心类 pa…

第2章 Class

Point结构体 //C语言写法 typedef struct point{float x;float y; }Point;Point a; a.x 1; a.y 2; //const表示p指向的对象里的值不能由p指针修改 void print(const Point* p){printf("%d %d\n", p -> x, p -> y); } print(&a);//想实现点的移动&#x…

使用Python绘制M2货币供应率曲线

M2广义货币供应量&#xff1a;流通于银行体系之外的现金加上企业存款、居民储蓄存款以及其他存款&#xff0c;它包括了一切可能成为现实购买力的货币形式&#xff0c;通常反映的是社会总需求变化和未来通胀的压力状态。近年来&#xff0c;很多国家都把M2作为货币供应量的调控目…

Go语言的命令

常用命令 假如你已安装了golang环境&#xff0c;你可以在命令行执行go命令查看相关的Go语言命令&#xff1a; Go语言是一门编译型语言&#xff0c;通过命令行工具来编译、运行和管理代码。以下是Go语言的一些常用命令及其用法&#xff1a; go run&#xff1a;用于编译并直接…

pycharm环境下打开Django内置的数据库Sqlite出错问题解决

问题描述 在数据库库文件中写入一条记录后&#xff0c;在pycharm的terminal终端下执行查看表的命令出错 执行语句为&#xff1a; 连接数据库报错 python manage.py dbshell CommandError: You appear not to have the sqlite3 program installed or on your path. Error:…

学习笔记——vue中使用el-dropdown组件报错

今天在工作中&#xff0c;发现使用el-select做的下拉框&#xff0c;下拉菜单展开后&#xff0c;鼠标点击下拉框之外的区域时&#xff0c;下拉菜单没有收起。然后&#xff0c;我打开控制台&#xff0c;发现了这个错误。 Uncaught TypeError: Cannot read properties of null (re…

Spring注解

什么是基于Java的Spring注解配置? 给一些注解的例子 基于Java的配置&#xff0c;允许你在少量的Java注解的帮助下&#xff0c;进行你的大部分Spring配置而非通过XML文件。 以Configuration 注解为例&#xff0c;它用来标记类可以当做一个bean的定义&#xff0c;被Spring IOC容…

SAP MM 根据采购订单反查采购申请

如何通过采购订单号查询到其前端的采购申请号。 首先从采购申请的相关报表着手&#xff0c;比如ME5A, 发现它是可以满足需求的。 例如&#xff1a;如下的采购订单&#xff0c; 该订单是由采购申请10003364转过来的。 如果想通过这个采购订单找到对应的采购申请&#xff0c;在…