JavaScript-事件-总结


JavaScript 事件是指用户与网页交互时触发的行为(如点击、输入),或浏览器自身的行为(如点击、输入),或浏览器自身的行为(如加载完成)。通过事件机制,可实现网页的动态响应。

一、事件绑定(注册事件)

为元素绑定事件处理函数,使其在事件触发时执行。主要有3种方式:

1. HTML 内联绑定(不推荐)

直接在 HTML 标签中通过事件属性绑定函数,耦合度高,不利于维护。

语法:

<元素 on事件名="函数名(参数)">

示例:

<button onclick="showMsg()">点击我</button>
<script>
	function showMsg() {
		alert("HTML 内联绑定触发")
	}
</script>

在这里插入图片描述
点击之后:
在这里插入图片描述

2.DOM 属性绑定(简单场景可用)

通过 JS 获取 DOM 元素后,直接给元素的事件属性赋值函数。
缺点:同一元素同一事件只能绑定一个函数,后绑定的会覆盖前一个。

语法:

元素.on事件名 = 函数

示例:
(先写第一个函数)

<button id="btn2">DOM属性绑定</button>
<script>
    const btn2 = document.getElementById('btn2')
    // 绑定事件
    btn2.onclick = function() {
        alert('DOM属性绑定触发')
    }
</script>

在这里插入图片描述

在这里插入图片描述
(然后写第二个函数)

<button id="btn2">DOM属性绑定</button>
<script>
    const btn2 = document.getElementById('btn2')
    // 绑定事件
    btn2.onclick = function() {
        alert('DOM属性绑定触发')
    }
    btn2.onclick = function() {
        alert('新函数覆盖旧函数')
    }
</script>

点击后只会弹出一次“新函数覆盖旧函数”。
不会先弹出“DOM属性绑定触发”之后再弹出“新函数覆盖旧函数”。
在这里插入图片描述

3. addEventListener (推荐)

W3C 标准方法,支持给同一元素同一事件绑定多个函数,按绑定顺序执行;还能指定事件捕获 / 冒泡阶段。

语法:

元素.addEventListener(事件名,处理函数,[userCapture])
  • 事件名:不含 on ,如 click、mouseover;
  • 处理函数:事件触发时执行的函数(可匿名或命名);
  • userCapture:可选,布尔值,true 表示在捕获阶段触发,false(默认)表示在冒泡阶段触发。

示例:

<script>
    const btn3 = document.getElementById('btn3')
    // 绑定第一个函数
    btn3.addEventListener('click',function(){
        console.log('第一个点击事件')
    })
    btn3.addEventListener('click',showLog)

    function showLog() {
        console.log('第二个点击事件')
    }
</script>

点击后控制台同时出现:
在这里插入图片描述


二、事件解绑(移除事件)

移除已绑定的事件处理函数,避免内存泄漏或意外触发。

1. DOM 属性解绑

直接将元素的事件属性赋值为 null,即可移除通过DOM属性绑定的事件。

语法:

元素.on事件名 = null

示例:

<button id="btn4">点击后解绑</button>
<script>
    const btn4 = document.getElementById('btn4')
    btn4.onclick = function() {
        alert('点击一次后解绑')
        // 解绑事件(后续点击无效)
        btn4.onclick = null
    }
</script>

点击一次后弹窗,后续点击都不弹出弹窗。
在这里插入图片描述

2. removeEventListener(对应addEventListener)

移除通过 addEventListner 绑定的事件,必须满足3个条件:

  1. 事件名与绑定一致;
  2. 处理函数为命名函数(匿名函数无法移除);
  3. useCapture 与绑定一致。

语法:

元素.removeEventListener(事件名, 处理函数, [useCapture]);

示例:

<button id="btn5">绑定/解绑</button>
<script>
    const btn5 = document.getElementById('btn5')
    // 命名处理函数(关键:匿名函数无法移除)
    function handleClick() {
        console.log('事件触发')
    }
    // 绑定事件
    btn5.addEventListener('click',handleClick)

    // 1秒后自动解绑
    setTimeout(() => {
        btn5.removeEventListener('click',handleClick)
        console.log('事件已解绑,后续点击无效')
    }, 3000)
</script>

在这里插入图片描述


三、事件流(捕获与冒泡)

当元素触发事件时,事件会按 “捕获阶段–>目标阶段–>冒泡阶段” 传播,这就是事件流。

  • 捕获阶段:事件从最顶层的 document 向下传播到目标元素。
  • 目标阶段:事件到达触发事件的目标元素。
  • 冒泡阶段:事件从目标元素向上传播回 document。

我们再回忆一下addEventListener 绑定事件的语法:

元素.addEventListener(事件名, 处理函数, [useCapture])

我们说过,第三个参数 useCapture 是布尔值,true表示在捕获阶段触发,false表示在冒泡阶段触发。

示例:

<div id="outer" style="padding: 20px; background-color: aquamarine;">
     <div id="inner" style="padding: 20px; background-color: aqua;">
         <button id="btn6">点击</button>
     </div>
 </div>

 <script>
     const outer = document.getElementById('outer')
     const inner = document.getElementById('inner')
     const btn6 = document.getElementById('btn6')

     // 捕获阶段触发(useCapture: true)
     outer.addEventListener('click',() => console.log('outer捕获'),true)
     inner.addEventListener('click',() => console.log('inner捕获'),true)


     // 冒泡阶段触发(useCapture: false)
     outer.addEventListener('click',() => console.log('outer冒泡'),false)
     inner.addEventListener('click',() => console.log('inner冒泡'),false)
     btn6.addEventListener('click',() => console.log('btn目标'))
 </script>

在这里插入图片描述

▲阻止事件冒泡
使用 event.stopPropagation( ) 阻止事件向上传播,避免父元素的事件被触发。

<div id="outer" style="padding: 20px; background-color: aquamarine;">
    <div id="inner" style="padding: 20px; background-color: aqua;">
        <button id="btn6">点击</button>
    </div>
</div>

<script>
    const outer = document.getElementById('outer')
    const inner = document.getElementById('inner')
    const btn6 = document.getElementById('btn6')

    // 捕获阶段触发(useCapture: true)
    outer.addEventListener('click',() => console.log('outer捕获'),true)
    inner.addEventListener('click',() => console.log('inner捕获'),true)


    // 冒泡阶段触发(useCapture: false)
    outer.addEventListener('click',() => console.log('outer冒泡'),false)
    inner.addEventListener('click',() => console.log('inner冒泡'),false)
    btn6.addEventListener('click',(event) => {
        console.log('btn目标')
        // 阻止冒泡到父元素
        event.stopPropagation()
    })
</script>

在这里插入图片描述

再举个例子:

<div id="parent" style="padding: 20px; background-color: aquamarine;">
    父元素
    <button id="btn7">点击我(不触发父元素事件)</button>
</div>

<script>
    const parent = document.getElementById('parent')
    const btn7 = document.getElementById('btn7')

    parent.onclick = () => alert('父元素被点击')
    btn7.onclick = function(event) {
        alert('按钮被点击')
        // 阻止事件冒泡到父元素
        event.stopPropagation()
    }
</script>

这是阻止事件冒泡到父元素的效果:
点击父元素,会弹出弹窗“父元素被点击”。
点击button按钮,只会弹出一次弹窗“按钮被点击”。
在这里插入图片描述
如果不阻止事件冒泡,会发生什么呢?
(我们一起把event.stopPropagation() 这行代码注释掉看一下效果)
结果是:
点击button按钮后,先弹出一个弹窗“按钮被点击”,然后再弹出一个弹窗“父元素被点击”。说明事件冒泡到父元素啦!

在这里插入图片描述

在这里插入图片描述


四、事件委托(事件代理)

利用事件冒泡特性,将子元素的事件统一绑定到父元素上,由父元素“代理”子元素的事件。

核心优势:

  • 减少事件绑定次数,优化性能;
  • 动态新增的子元素无需重新绑定事件。

实现步骤:

  1. 找到所有子元素的共同父元素;
  2. 给父元素绑定事件;
  3. 在事件处理函数中,通过 event.target 判断触发事件的子元素(目标元素);
  4. 若为目标子元素,则执行对应逻辑。

语法关键:
event.target ——指向触发事件的“最具体” 的元素(子元素)。

示例(列表项点击事件委托):

<ul id="list">
    <li>列表项1</li>
    <li>列表项2</li>
    <li>列表项3</li>
</ul>
<button id="addLi">新增列表项</button>

<script>
    const list = document.getElementById('list')
    const addLi = document.getElementById('addLi')

    // 1.给父元素ul绑定事件(只绑定1次)
    list.addEventListener('click',function(event) {
        // 2.判断触发事件的是否是 li 子元素
        if(event.target.tagName === 'LI') {
            // 3.处理li的点击逻辑
            alert('点击了'+ event.target.textContent)
        }
    })

    // 动态新增列表项(无需重新绑定事件)
    addLi.onclick = function() {
        const newLi = document.createElement('li')
        newLi.textContent = '新列表项' + (list.children.length + 1)
        list.appendChild(newLi)
    }
</script>

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值