「JavaScript基础」一文彻底搞懂JS的事件流以及事件模型

目录


在JavaScript中,事件流和事件模型是处理用户交互的关键概念。深入理解这些概念将使你能够更好地处理和响应用户的动作。本文将详细介绍JavaScript的事件流和事件模型。

事件

在了解什么是事件流之前,我们先了解一下什么是事件

事件是文档或浏览器窗口中发生的一些特定的交互瞬间

HTML事件就是发生在HTML元素上的事情

当在HTML中使用javaScript时,javaScript能够应对这些事件

比如鼠标点击、键盘按键、页面加载、表单提交...

事件机制

事件绑定、事件监听、事件委托(事件代理)

一、事件绑定

事件绑定是指将事件处理函数附加到特定的DOM元素上。

在JavaScript中,有以下几种绑定事件的方法(以click为例):

  • 在DOM元素中直接绑定

    可以直接在DOM元素上绑定某个事件

    html 复制代码
    <div onclick="hello()">click me</div>
    <script>
    function hello(){
    	alert("hello world!");
    }
    </script>
  • 在JavaScript代码中绑定

    在JavaScript代码中绑定事件可以使JavaScript代码与HTML标签分离,文档结构清晰,便于管理和开发。

    html 复制代码
    <div id="btn">click me</div>
    <script>
    document.getElementById("btn").onclick = hello
    function hello(){
    	alert("hello world!");
    }
    </script>
  • 绑定事件监听函数

    使用 addEventListener()attachEvent()【IE标准】 来绑定事件监听函数。

    👇下面请看事件监听

二、事件监听

事件监听的优点

  1. 可以绑定多个事件
    btn1.addEventListener("click",hello1)
    btn2.addEventListener("click",hello2)
  2. 可以解除相应的绑定
    addEventListener() => removeEventListener()
    attachEvent() => detachEvent()

element.addEventListener(event, function, useCapture)

  • event : (必需)事件名,支持所有 DOM事件

  • function:(必需)指定要事件触发时执行的函数

  • useCapture:(可选)指定事件是否在捕获或冒泡阶段执行。true => 在事件捕获阶段调用;false[默认] => 在事件冒泡阶段调用

  • 注意:IE8以下不支持

  • 示例👇

    html 复制代码
    <div id="btn">click me</div>
    <script>
    document.getElementById("btn").addEventListener("click", hello);
    function hello(){
    	alert("hello world!");
    }
    </script>

element.attachEvent(event, function) 【IE标准】

  • event:(必需)事件类型。需加on,例如:onclick

  • function:(必需)指定要事件触发时执行的函数。

  • 示例👇

    html 复制代码
    <div id="btn1">click me</div>
    <script>
    document.getElementById("btn1").attachEvent("onclick",hello);
    function hello(){
    	alert("hello world!");
    }
    </script>

三、事件委托

事件监听的优点

  1. 提高JavaScript性能。事件委托可以显著的提高事件的处理速度,减少内存的占用。 【DEMO】
  2. 动态的添加DOM元素,不需要因为元素的改动而修改事件绑定。

事件委托就是利用冒泡的原理,把事件加到父元素或祖先元素上,触发执行效果。

示例👇

html 复制代码
<div id="btn">click me</div>
<script>
   const btn = document.getElementById("btn");
   document.onclick = function(event){
       event = event || window.event;
       var target = event.target || event.srcElement;
       if(target == btn){
           hello()
       }
   }

function hello(){
	alert("hello world!");
}

事件流

事件流 是从页面中接收事件的顺序。

事件流模型

DOM事件流规范规定事件流分为 3 个阶段:

  1. 事件捕获阶段:事件从上往下查找对应元素,直到捕获到事件
  2. 处于目标阶段:目标元素后执行事件对应的处理函数
  3. 事件冒泡阶段:事件从目标元素开始冒泡


Tips: 在 DOM 事件流中,实际的目标(元素)在捕获阶段不会收到事件。这是因为捕获阶段从document到元素就结束了。下一阶段,即会在元素上触发事件的"处于目标"阶段,通常在事件处理时被认为是冒泡阶段的一部分。然后冒泡阶段开始,事件反向传播至文档。


DOM事件处理

DOM节点中有了事件,那我们就需要对事件进行处理。

DOM0

DOM0级事件具有极好的跨浏览器优势,会以最快的速度绑定。

  1. 内联模型(行内绑定):将函数名直接作为html标签中属性的属性值

    html 复制代码
    <div onclick="handleClick" >Click Me</div>
    <script>
    function handleClick(){
        alert("hello world!");
    }
    </script>
  2. 脚本模型(动态绑定),通过在JS中选中某个节点,然后给节点添加onclick属性。

    html 复制代码
    <div id="btn">Click Me</div>
    <script>
    const btn = document.getElementById("btn");
    btn.onclick = handleClick()
    function handleClick(){
        alert("hello world!");
    }
    </script>

Tips1: 使用 on 开头的事件,同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数。

html 复制代码
<div id="btn">Click Me</div>
<script>
const btn = document.getElementById("btn");
btn.onclick = handleClick()
btn.onclick = handleClick2()
function handleClick(){
    alert("hello world!");
}
function handleClick2(){
    alert("hello world222!");
}
// 输出 hello world222!
</script>

Tips2: DOM0级只支持冒泡阶段

html 复制代码
<div id="btn1" style="height: 200px;width: 200px;background: red;">
    btn1
    <div id="btn2" style="height: 150px;width: 150px;background: green;">
        btn2
        <div id="btn3" style="height: 100px;width: 100px;background: blue;">
            btn3
        </div>
    </div>
</div>
<script>
    const btn1 = document.getElementById("btn1");
    const btn2 = document.getElementById("btn2");
    const btn3 = document.getElementById("btn3");
    btn1.onclick=function(){
        console.log(1)
    }
    btn2.onclick=function(){
        console.log(2)
    }
    btn3.onclick=function(){
        console.log(3)
    }
</script>

👇 运行效果

👇 当点击 btn3 时:

👇 当点击 btn1 时:

👉 可以发现:最先触发的是最底层 btn1的事件,最后才是顶层 btn3 的事件,因此很明显是事件冒泡 。SO... DOM0级只支持冒泡阶段.


DOM2

定义了两个方法:

  • addEventListener() => 添加事件侦听器
  • removeEventListener() => 移除事件侦听器
  • 具体使用请上滑至 【事件监听】

大多数情况下,事件处理程序会被添加到事件流的冒泡阶段 ,主要原因是跨浏览器兼容性好。

把事件处理程序注册到捕获阶段通常用于在事件到达其指定目标之前拦截事件。如果不需要拦截,则不要使用事件捕获。

🫠 回头看:

html 复制代码
<div id="btn1" style="height: 200px;width: 200px;background: red;">
    btn1
    <div id="btn2" style="height: 150px;width: 150px;background: green;">
        btn2
        <div id="btn3" style="height: 100px;width: 100px;background: blue;">
            btn3
        </div>
    </div>
</div>
<script>
    const btn1 = document.getElementById("btn1");
    const btn2 = document.getElementById("btn2");
    const btn3 = document.getElementById("btn3");
    btn1.addEventListener('click',function (){
		console.log(1)
	},true)
	btn2.addEventListener('click',function (){
		console.log(2)
	},true)
	btn3.addEventListener('click',function (){
		console.log(3)
	},true)
</script>

👇 当点击 btn3 时:【DOM2中的顺序和DOM0中的顺序反过来了,最外层的btn最先触发,因为 addEventListener 最后一个参数是true,捕获阶段进行处理~】


IE 事件处理程序

IE 实现了与 DOM2 类似的方法

  • attachEvent() => 附加事件
  • detachEvent() => 剥离事件
  • 具体使用请上滑至 【事件监听】
js 复制代码
const btn = document.getElementById("btn");
btn.attachEvent("onclick", function() {
  console.log("hello world!");
});

需要注意以下几点:

  • 使用 attachEvent() 时,事件处理程序是在全局作用域中运行的,因此 this 等于 window。这个差异对编写跨浏览器代码是非常重要的。
  • 使用 attachEvent() 方法也可以给一个元素添加多个事件处理程序。事件处理程序会以添加它们的顺序反向触发。
  • 使用 attachEvent() 添加的事件处理程序将使用 detachEvent() 来移除, 只要提供相同的参数。匿名函数也无法移除。

常见的事件

HTML 事件参考手册

未完待续...

相关推荐
Myli_ing20 分钟前
考研倒计时-配色+1
前端·javascript·考研
余道各努力,千里自同风23 分钟前
前端 vue 如何区分开发环境
前端·javascript·vue.js
PandaCave30 分钟前
vue工程运行、构建、引用环境参数学习记录
javascript·vue.js·学习
软件小伟32 分钟前
Vue3+element-plus 实现中英文切换(Vue-i18n组件的使用)
前端·javascript·vue.js
醉の虾1 小时前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js
张小小大智慧1 小时前
TypeScript 的发展与基本语法
前端·javascript·typescript
hummhumm1 小时前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
asleep7011 小时前
第8章利用CSS制作导航菜单
前端·css
hummhumm1 小时前
第 28 章 - Go语言 Web 开发入门
java·开发语言·前端·python·sql·golang·前端框架
幼儿园的小霸王2 小时前
通过socket设置版本更新提示
前端·vue.js·webpack·typescript·前端框架·anti-design-vue