js:事件流

news/2025/1/8 11:43:50 标签: javascript, 前端, 开发语言

事件流

事件流是指事件完整执行过程中的流动路径

一个事件流需要经过两个阶段:捕获阶段,冒泡阶段

捕获阶段是在dom树里获取目标元素的过程,从大到小

冒泡阶段是获取以后回到开始,从小到大,像冒泡一样

实际开发中大部分只用到了冒泡阶段

事件捕获

从Dom的根元素开始去执行对应的事件(从外到里)

事件捕获需要写对应代码才能看到效果
javascript">dom.addEventListener('事件类型',function(){},true)

true是捕获,默认是false

false是冒泡阶段,如果你只使用 L0 事件监听,那么事件监听器只会在冒泡阶段触发,不会在捕获阶段触发,因为ie等浏览器不支持捕获,或者说没有冒泡和捕获这个概念

1、事件覆盖情况:

L0(传统on<事件类型>注册):对于同一个对象,如果后面注册了相同类型的事件,它会覆盖前面注册的事件。例如,如果一个元素上先后注册了两个onclick事件,那么只有后面注册的那个事件会被触发。
L2(事件监听注册addEventListener):使用这种方法注册事件时,后面注册的同类型事件不会覆盖前面注册的事件。这意味着,可以在同一个元素上注册多个相同类型的事件,并且它们都会被触发。
2、事件解绑方式:

L0:直接使用null赋值就可以实现事件的解绑,例如对象.onclick = null。
L2:解绑事件需要使用removeEventListener方法,并传入相应的事件类型、事件处理函数以及捕获或冒泡阶段(如果绑定时指定了的话)。需要注意的是,如果使用匿名函数作为事件处理函数,那么将无法解绑该事件,因为无法再次引用到相同的匿名函数。
3、执行阶段:

L0:注册的事件都是在冒泡阶段执行的。
L2:注册事件时可以通过第三个参数来指定事件是在捕获阶段还是冒泡阶段执行。如果不指定第三个参数或传入false,则事件默认在冒泡阶段执行;如果传入true,则事件在捕获阶段执行。

事件冒泡

事件冒泡:当一个元素的事件被触发时,同意的事件将会在该元素的所有祖先元素依次触发

javascript">dom.addEventListener('事件类型',function(){})

L2事件监听的第三个参数是false

阻止冒泡

冒泡会把事件传递到父元素,有时候我们需要将事件的影响限制到当前元素里,就需要阻止事件冒泡

阻止事件冒泡首先要拿到事件对象:

这个方法不光可以阻断冒泡,可以阻断其他时间流动传播,就是说也可以阻断捕获阶段的事件传播

在哪里截断就在哪里加这句方法,记住此方法要调用事件对象e

阻止默认行为

有些网页元素有默认行为,比如右键弹出菜单栏这种,如果想阻止默认事件,就需要加上

解绑事件

之前我们只学了监听事件,有时候监听结束后不需要监听了,就需要解绑事件

在L0旧语法里是这么解绑的

L2里使用addEventListener()添加监听,就要使用removeEventListener()来解绑

javascript">removeEventListener(事件类型,事件处理函数,[获取捕获或冒泡阶段])

因为要添加事件处理函数作为参数,匿名函数没有名字,所以不能被解绑

加了中括号的参数表示可写可不写

fn不能加小括号,函数回调不用加小括号

鼠标经过事件的区别

在只有一级,没有父子级的时候,二者没什么区别

mouseover和mouseout在父子级都存在的时候会有冒泡效果,自己的效果会冒泡到父级上

mouseenter和mouseleae则没有这个问题,推荐使用这种用法

事件委托

事件相对于快递,给很多元素绑定事件的时候,在以前我们是才能for循环的方式,给每个元素绑定事件,就相当于每个快递1对1的送给每个人;但是有了驿站,就可以把快递托给驿站,就不需要一个一个的注册事件,这叫事件委托,此时的驿站和个人是一种父子级的关系

事件委托是一种事件注册的小技巧

原理:当我们想要给很多个子元素注册一样的事件的时候,例如点击小圆点切换图片(轮播图),就需要单独给每个小圆点添加监听;但是给父元素添加监听的时候,我们触发子元素的时候,会冒泡到父元素,然后触发父元素绑定的事件。

所以事件委托的原理就是事件冒泡

这样可以提高性能,减少注册次数

写一个看看:

父元素里的子元素在监听到事件以后会执行父元素绑定的函数:

javascript"> const box = document.querySelector('div')
        box.addEventListener('click', function (e) {
            //alert('点上了')
            console.log(e.target);

        })

点击不同的span,e.target的属性值也不一样

根据事件对象的特性改变span的背景颜色:

javascript"> <script>
        const box = document.querySelector('div')
        box.addEventListener('click', function (e) {
            //alert('点上了')
            console.log(e.target);
            e.target.style.backgroundColor='purple'

        })
    </script>

但是这样有一个问题:父级绑定了以后所有的子级触发事件后都会执行父元素绑定的函数,有时候并不是所有的子级都需要触发,类名不同或者标签不同的元素不需要这个事件,怎么做到分离父级和  一部分子级?

事实证明人类对事件对象的开发程度不足1%:

展开这个箭头:

可以发现这些目标是有nodeName的,我们可以靠nodeName来区分,只对span添加委托:

javascript"> const box = document.querySelector('div')
        box.addEventListener('click', function (e) {
            //alert('点上了')
            //console.log(e);
            if(e.target.nodeName==='SPAN')
            e.target.style.backgroundColor='purple'

        })

使用事件委托来重做一下之前的小圆点切换图片功能:

一个需要注意的点:之前我们是用i来访问选择的li,现在没有i了,怎么知道选中的是哪个li?

使用自定义属性

定义:

javascript"><div data-id="0"></div>

获取:

javascript">   const div=document.querySelector('div')
        console.log(div.dataset.id)

像这样,来访问li

但是!孩子们,注意一个问题,此时你获得的data-id是字符串,不能之间当数字使,取过来会当字符串使用

js:

javascript">  //事件委托写法
        const ul = document.querySelector('ul')
        ul.addEventListener('click', function (e) {
            //console.log(e.target.dataset.id);
            // 隐式转换,转换为数字型
            const id =+e.target.dataset.id
            toggle(id)
            clearInterval(timeId)
            i = id
            timeId = setInterval(function () {

                next.click()
            }, 1000)
        })

html:

  <ul class="slider-indicator">
                <li class="active" data-id="0"></li>
                <li data-id="1"></li>
                <li data-id="2"></li>
                <li data-id="3"></li>
            </ul>

其它事件

除了之前学的鼠标事件、键盘事件、焦点事件、文本事件等,还有其他事件

页面加载事件

在打开一个网页的时候,会有许多外部资源被加载,比如图片、外联CSS、JavaScript等,我们需要等这些元素加载完在打开网页;或者在body前面写的js没办法加载dom树,所以我们需要等待(load)

事件名:load

javascript">window.addEventListener('load',function(){
            
        })

load事件的意思是等加载完毕,再去执行回调函数

但是现在没什么人这么写,因为如果要等待dom树加载完为什么要写body前面呢?直接写在body后面就不用操心这个问题了

有时候网络出了问题或者网页加载比较慢的时候,网页里会先加载出来html元素,css和js等还没有渲染出来。这种只加载出html骨架就触发的事件叫DOMContentLoaded

相比load事件,DOMContentLoaded事件触发会比load快,因为不用等样式表、图片等外部资源加载好,用户体验更好

javascript">document.addEventListener('DOMContentLoaded',function(){

})

元素滚动事件

页面内有些元素是根据滚动在不同地方的时候出现的,这个关于网页滚动的事件就叫scroll(滚动事件)

首先要确定的是谁在滚动?window

javascript">   window.addEventListener('scroll', function () {
            console.log('页面滚动了');

        })

每滚动1像素就会检测到:

介绍页面的新属性

srcollLeft:左侧被卷去的距离

srcollTop:顶部被卷去的距离

出现的数字有两个特点:不带单位、可读写(简称可访问可赋值)

可以通过页面滚动的距离来设置元素的显示:

javascript">   const elevator = document.querySelector('.xianshi')
        window.addEventListener('scroll', function () {
            //console.log('页面滚动了');
            //console.log(document.documentElement.scrollTop)
            let top = document.documentElement.scrollTop
            if (top >= 300) {
                elevator.style.opacity = 1
            }
        })

说明数据可读可写

页面尺寸事件

随着页面的放大和缩小触发事件

通过clientWidth和clientHeight来获取盒子的宽度:

但是clientWidth和clientHeight是不包含padding和border的

而offsetWidth和offsetHeight则可以包含padding和border,可以获取宽高

获取尺寸的数据为数值,可以方便计算

前提是盒子为可视化盒子,如果盒子被隐藏起来了,获取的数值为0

offsetLeft和offsetTop可以获取元素距离定位父级元素(如果最近一级的父级元素不带定位,就往上找一级,直到找到带定位的父级元素,测量和该元素的距离为offsetLeft的值)的左、上距离,是只读属性做不了计算

demo

解决问题:初次没有active类的报错问题

解决办法:先获取类,分情况讨论:有active这个类/没有这个类

如果当前对象没有这个类,就为他添加此类/如果有这个类就去除

html{
  scroll-behavior: smooth;
  /* 滑动流畅 */
}

在点击事件之后,电梯字体的颜色也要改变,来告诉用户当前处于哪个模块

所以只要一滚动,就要移除当前的active,在滚动之后再加上

本来我觉得单独获取与for循环获取还是后者更方便,但是品客老师说这样不方便后期的修改,降低的代码的可用性

javascript">//电梯函数模块
    (function () {
      const elevator = document.querySelector('.xtx-elevator')
      window.addEventListener('scroll', function () {
        const n = document.documentElement.scrollTop
        // if (n > 300) {
        //   elevator.style.opacity = 1
        // } else {
        //   elevator.style.opacity = 0
        // }
        elevator.style.opacity = n >= 300 ? 1 : 0
      })
      const backTop = document.querySelector('#backTop')
      backTop.addEventListener('click', function () {
        document.documentElement.scrollTop = 0
        //window.scrollTo(0, 0)将页面滚动到指定坐标
      })
    })();

    (function () {
      //模块变色和点击跳转效果
      const list = document.querySelector('.xtx-elevator-list')
      list.addEventListener('click', function (e) {
        if (e.target.tagName === 'A' && e.target.dataset.name) {
          const old = document.querySelector('.xtx-elevator-list .active')
          // if (old) old.classList.remove('active')
          // e.target.classList.add('active')
          //console.log(document.querySelector(`.xtx_goods_${e.target.dataset.name}`).offsetTop)
          const top = document.querySelector(`.xtx_goods_${e.target.dataset.name}`).offsetTop
          document.documentElement.scrollTop = top
        }
      })
      window.addEventListener('scroll', function () {
        const old = document.querySelector('.xtx-elevator-list .active')
        if (old) old.classList.remove('active')
        // 获取所有 <li> 元素
        const news = document.querySelector('.xtx_goods_new')
        const popular = document.querySelector('.xtx_goods_popular')
        const brand = document.querySelector('.xtx_goods_brand')
        const topic = document.querySelector('.xtx_goods_topic')
        const n=document.documentElement.scrollTop
        if(n>=news.offsetTop&&n<popular.offsetTop){
          document.querySelector('[data-name=new]').classList.add('active')
        }else if(n>=popular.offsetTop&&n<brand.offsetTop){
          document.querySelector('[data-name=popular]').classList.add('active')
        }else if(n>=brand.offsetTop&&n<topic.offsetTop){
          document.querySelector('[data-name=brand]').classList.add('active')
        }else if(n>=topic.offsetTop){
          document.querySelector('[data-name=topic]').classList.add('active')
        }
      })
    })();

就在此时此刻,我的外卖被偷了

我永远痛恨偷外卖的4全家


http://www.niftyadmin.cn/n/5816275.html

相关文章

Bi-Encoder vs. Cross-Encoder

Bi-Encoder vs. Cross-Encoder Bi-Encoder 和 Cross-Encoder 是两种常见的模型架构&#xff0c;主要用于自然语言处理&#xff08;NLP&#xff09;中的文本匹配、问答、检索等任务。它们的主要区别在于如何处理输入文本以及计算相似度的方式。 1. Bi-Encoder&#xff08;双编…

近二百年历史传承,内藤酿造七醸烧用匠心打动中国市场

2025年1月5日&#xff0c;一场别开生面的蒸馏酒鉴赏会在上海隆重举行&#xff0c;标志着源自海外的蒸馏酒品牌——赏己七醸烧在中国市场的布局开启新的篇章。内藤酿造这家拥有近200年历史的综合性酒企&#xff0c;以其自主研发的御酵母、独特的七醸工艺、无与伦比的口感与中度白…

Linux Red Hat 7.9 Server安装Docker

1、安装必要的一些系统工具 sudo yum install -y yum-utils 2、添加软件源信息 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 3、安装Docker sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx…

ROS2+OpenCV综合应用--11. AprilTag标签码跟随

1. 简介 apriltag标签码追踪是在apriltag标签码识别的基础上&#xff0c;增加了小车车体运动的功能&#xff0c;控制车体从而使摄像头会保持标签码在视觉中间左右运动&#xff0c;在根据物体在摄像头成像近大远小的原理根据这一特性&#xff0c;从而实现标签码跟随功能。 2. 启…

【2025最新】网络安全攻防实战:护网行动经验与策略解析

博客内容多从网络搜集&#xff0c;结合个人学习进行总结&#xff0c;如有侵权请即时联系&#xff0c;立刻删除(〃‘▽’〃) 整理不易&#xff0c;虚心求教&#xff0c;欢迎各位大佬指导( • ̀ω•́ )✧ 护网行动基本介绍 什么护网行动护网经验分享攻防入侵路径红队攻击方式蓝…

EasyExcel监听器详解

EasyExcel监听器详解 EasyExcel 监听器概述 EasyExcel 是一个 Java 语言编写的简单易用的 Excel 操作框架。它的监听器机制允许开发者在读取或写入 Excel 文件时&#xff0c;以事件驱动的方式来处理数据&#xff0c;而不是一次性将整个 Excel 文件的数据加载到内存中。这种方式…

计算机网络之---网络拓扑

什么是网络拓扑 为什么需要网络拓扑 网络拓扑有哪些 什么是网络拓扑 网络拓扑 是指网络中各设备&#xff08;如计算机、路由器、交换机等&#xff09;如何连接以及它们之间数据流动的结构和布局。它是网络设计的一个关键方面&#xff0c;决定了网络的性能、可扩展性、可靠性…

耗时一天,我用AI开发了AI小程序

小码哥从事前后端开发近十年&#xff0c;但是随着技术的更新迭代&#xff0c;有时候没有时间和精力去优化UI、实现一些前后端功能&#xff0c;以及解决一些bug。特别是我想开发小码哥AI的移动端&#xff0c;但觉得自己没有那么多时间去研究移动端了&#xff0c;准备放弃了&…