六维教程

JavaScript 事件对象

上一篇文章讲了用 addEventListener 绑定事件,事件发生时函数会被调用。但光知道”点击了”还不够,很多时候代码需要知道点击的是哪个元素、事件类型是什么、坐标在哪。这些细节全部装在一个对象里,这就是事件对象。

事件处理函数的第一个参数就是事件对象,浏览器每次调用处理函数时都会传入它。约定俗成把参数写成 event,或者简写成 e。

认识事件对象

事件对象由浏览器自动创建,描述本次事件的全部细节。处理函数不需要自己创建它,直接在参数位置接收就行。

<button id="btn">查看事件</button>
<script>
  const btn = document.getElementById('btn')
  btn.addEventListener('click', (e) => {
    console.log(e)
  })
</script>

点击按钮后打开控制台,展开打印出来的对象,可以看到 type、target、timeStamp 等字段。不同事件类型,对象里的字段也不同。键盘事件有 keyCode,鼠标事件有 clientX 和 clientY。

target 与 type 属性

事件对象最常用的两个属性是 target 和 type。type 是事件类型字符串,target 是触发事件的元素。

典型场景是页面里有多个按钮,点击后输出点到了谁。

<button class="item">按钮 A</button>
<button class="item">按钮 B</button>
<button class="item">按钮 C</button>
<script>
  const buttons = document.querySelectorAll('.item')
  buttons.forEach((button) => {
    button.addEventListener('click', (e) => {
      console.log('事件类型是', e.type)
      console.log('点击的元素是', e.target.textContent)
    })
  })
</script>

点击按钮 B,控制台输出”事件类型是 click”和”点击的元素是 按钮 B”。用 e.target 就能拿到实际被点击的元素,再通过它的属性读取信息。

阻止默认行为 preventDefault

浏览器对部分事件有默认行为。点击 a 标签会跳转页面,提交表单会刷新页面。有些场景不想要这些默认行为,可以用 preventDefault 阻止。

最常见的例子是表单校验。提交前先检查输入,不合格就不让表单真的提交。

<form id="reg">
  <input type="text" id="email" placeholder="请输入邮箱">
  <button type="submit">注册</button>
</form>
<p id="msg"></p>
<script>
  const form = document.getElementById('reg')
  const email = document.getElementById('email')
  const msg = document.getElementById('msg')
  form.addEventListener('submit', (e) => {
    const value = email.value
    if (!value.includes('@')) {
      e.preventDefault()
      msg.textContent = '邮箱格式不正确,请检查后重试'
    }
  })
</script>

输入不包含 @ 的内容提交,页面不会刷新,而是显示提示文字。校验通过时什么都不做,表单正常提交。

同样的手法可以阻止 a 标签跳转。点击链接只记录日志,不跳转页面。

<a id="link" href="https://example.com">点我不会跳转</a>
<script>
  const link = document.getElementById('link')
  link.addEventListener('click', (e) => {
    e.preventDefault()
    console.log('默认跳转被阻止了')
  })
</script>

target 与 currentTarget 的区别

这是新手最容易混淆的一对属性,必须讲清楚。target 是事件实际发生的元素,currentTarget 是绑定监听的元素。当事件由子元素触发而监听绑在父元素上时,两者就不同了。

先看例子。父容器绑定监听,里面有三个子元素。

<div id="parent" style="padding: 20px; background: #eee;">
  <div id="child1">子元素 1</div>
  <div id="child2">子元素 2</div>
  <div id="child3">子元素 3</div>
</div>
<script>
  const parent = document.getElementById('parent')
  parent.addEventListener('click', (e) => {
    console.log('target 是', e.target.id)
    console.log('currentTarget 是', e.currentTarget.id)
  })
</script>

点击子元素 2,控制台输出”target 是 child2”和”currentTarget 是 parent”。事件发生在 child2 上,所以 target 是 child2,而监听绑在 parent 上,所以 currentTarget 是 parent。

一句话总结。target 回答”事件发生在谁身上”,currentTarget 回答”监听绑在谁身上”。只有点击监听元素本身时两者才相同。实际开发中判断点到了哪个具体元素用 target,要拿到绑定监听的元素本身用 currentTarget。两者作用不同,混用会出现难以排查的 bug。

小结

事件对象是处理函数的第一个参数,浏览器自动传入,描述事件的细节。e.target 表示事件实际发生的元素,e.type 表示事件类型。e.preventDefault 可以阻止表单刷新、链接跳转等默认行为。target 与 currentTarget 不同,target 是事件发生元素,currentTarget 是监听绑定元素,父子元素场景下两者通常不一样。

上一篇
JavaScript 事件是什么
下一篇
JavaScript 事件冒泡与捕获