章节索引 :

DOM 事件对象

Event 对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。(W3C)

事件对象会在事件被触发时获得,对象包含了当前事件的一些信息,如点击事件可以获取到点击的位置,键盘输入事件可以获取到按下的键。

1. 获取事件对象

在给 DOM 节点绑定事件时,需要传递一个事件处理器,其本质上是个函数,在事件触发时被调用。

在事件处理器被调用时,默认就会传递一个参数,这个参数就是事件对象。

实例演示
预览 复制
复制成功!
<input type="text" class="input-here">

<div class="log"></div>

<script>
  var inputEle = document.querySelector('.input-here');
  var logEle = document.querySelector('.log');

  inputEle.onkeydown = function(event) {
    var ele = document.createElement('p');

    ele.innerText = '按下了' + event.keyCode;

    logEle.appendChild(ele);
  }

  inputEle.addEventListener('keyup', function(event) {
    var ele = document.createElement('p');

    ele.innerText = '弹起了' + event.keyCode;

    logEle.appendChild(ele);
  });
</script>
运行案例 点击 "运行案例" 可查看在线运行效果

图片描述

输入一个字符的动作包含按下键松开键,对应的事件就是 onkeydownonkeyup,如果使用二级 DOM 事件,则可以不加 on 前缀。

例子中的事件处理器接收了一个参数,这个参数就是事件对象,参数名是可以随意的,一般情况下开发者会选择 e 或者 event 作为参数名。

onkeydownonkeyup 是键盘相关的事件,所以可以获取到按下的键是哪个,对应的就是事件对象下的 keyCode 属性。

keyCode 属性是按下键的 ASCII 码,如数字 1 对应的就是 49, 数字2对应的是 50。具体可以参阅 ASCII 映射表。

2. 常用的事件对象下的属性和方法

以下内容会涉及到事件流相关的内容,可以参阅 DOM 事件流章节。

在符合 DOM2 标准的浏览器中,事件对象都具有以下属性和方法。

2.1 属性

2.1.1 target

target表示当前事件最终捕获到的目标。

实例演示
预览 复制
复制成功!
<div class="a">
  我是第一个节点 a
  <div class="b">
    我是第二个节点 b
    <div class="c">
      我是第三个节点 c
      <div class="d">
        我是第四个节点 d
        <div class="e">
          我是第五个节点 e
          <div class="f">
            我是最里面的一个元素 f
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

<div class="result" style="margin-top: 16px;"></div>

<script>
  var resultEle = document.querySelector('.result');

  document.querySelector('.a').addEventListener('click', function(e) {
    resultEle.innerText = '捕获到的元素类名是' + e.target.className;
  });
</script>
运行案例 点击 "运行案例" 可查看在线运行效果

图片描述

可以看到事件绑定在类名为 a 的节点上,点击其子节点的时候,子节点就是最终捕获到的元素。

2.1.2 currentTarget

通过 currentTarget 可以获取到目前触发事件的元素。

实例演示
预览 复制
复制成功!
<div class="a">
  我是第一个节点 a
  <div class="b">
    我是第二个节点 b
    <div class="c">
      我是第三个节点 c
      <div class="d">
        我是第四个节点 d
        <div class="e">
          我是第五个节点 e
          <div class="f">
            我是最里面的一个元素 f
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

<div class="result" style="margin-top: 16px;"></div>

<script>
  var resultEle = document.querySelector('.result');

  document.querySelector('.a').addEventListener('click', function(e) {
    resultEle.innerText = [
      '当前触发事件的元素的类名是:',
      e.currentTarget.className,
      '。当前捕获到的元素类名是:',
      e.target.className,
    ].join('');
  });
</script>
运行案例 点击 "运行案例" 可查看在线运行效果

图片描述

不论点击的是哪个子节点,currentTarget 都是表示当前触发事件的节点。

2.2 方法

2.2.1 stopPropagation

调用此方法就会阻止事件的冒泡,使用到的场景大多为某个父元素和元素本身绑定了相同事件时。

实例演示
预览 复制
复制成功!
<style>
  .list {
    width: 300px;
    margin: 0 auto;
  }

  .list .item {
    width: 100%;
    border: 1px dashed #4caf50;
    border-bottom: 0;
    border-radius: 2px;
    padding: 16px;
  }

  .list .item:last-child {
    border-bottom: 1px dashed #4caf50;
  }

  .list .item button {
    border-radius: 2px;
    font-size: 14px;
    color: #666;
    outline: none;
  }

  .list .item button:active {
    background: #eee;
  }
</style>

<div class="list">
  <div class="item">
    <p>一句简单的介绍。</p>
    <button>点击我删除这条</button>
  </div>

  <div class="item">
    <p>两句简单的介绍。两句简单的介绍。</p>
    <button>点击我删除这条</button>
  </div>
</div>

<script>
  var items = document.querySelectorAll('.list .item');
  var btns = document.querySelectorAll('.list .item button');

  items.forEach(function(item) {
    item.addEventListener('click', function() {
      alert('马上进入到详情');
    });
  });

  btns.forEach(function(btn) {
    btn.addEventListener('click', function() {
      var parent = btn.parentNode;

      parent.parentNode.removeChild(parent);
    });
  });
</script>
运行案例 点击 "运行案例" 可查看在线运行效果

图片描述

上述例子,在点击按钮的时候,虽然完成了删除操作,但还是会弹出一个框,触发到了父级的事件,这是冒泡特性导致的,所以需要阻止向上冒泡,

实例演示
预览 复制
复制成功!
<style>
  .list {
    width: 300px;
    margin: 0 auto;
  }

  .list .item {
    width: 100%;
    border: 1px dashed #4caf50;
    border-bottom: 0;
    border-radius: 2px;
    padding: 16px;
  }

  .list .item:last-child {
    border-bottom: 1px dashed #4caf50;
  }

  .list .item button {
    border-radius: 2px;
    font-size: 14px;
    color: #666;
    outline: none;
  }

  .list .item button:active {
    background: #eee;
  }
</style>

<div class="list">
  <div class="item">
    <p>一句简单的介绍。</p>
    <button>点击我删除这条</button>
  </div>

  <div class="item">
    <p>两句简单的介绍。两句简单的介绍。</p>
    <button>点击我删除这条</button>
  </div>
</div>

<script>
  var items = document.querySelectorAll('.list .item');
  var btns = document.querySelectorAll('.list .item button');

  items.forEach(function(item) {
    item.addEventListener('click', function() {
      alert('马上进入到详情');
    });
  });

  btns.forEach(function(btn) {
    btn.addEventListener('click', function(e) {
      // 阻止冒泡
      e.stopPropagation();

      var parent = btn.parentNode;

      parent.parentNode.removeChild(parent);
    });
  });
</script>
运行案例 点击 "运行案例" 可查看在线运行效果

图片描述

2.2.2 preventDefault

此方法可以取消事件的默认行为,比如超链接的点击,会发生跳转,跳转动作就是默认行为。

给超链接绑定点击事件,调用事件对象下的 preventDefault 属性,默认行为就会取消,即不会发生跳转。

实例演示
预览 复制
复制成功!
<a href="https://imooc.com">冲鸭!!前往慕课网!!</a>

<script>
  var aTag = document.querySelector('a');

  aTag.onclick = function(e) {
    e.preventDefault();

    alert('跳转被终止!');
  };
</script>
运行案例 点击 "运行案例" 可查看在线运行效果

图片描述

3. 兼容性问题

早期IE下的事件模型与 DOM 标准提供的有些不同。

如事件对象,在 IE8 之前并不是通过传递给事件处理器获取的,而是要通过 window.event 获取。

实例演示
预览 复制
复制成功!
<div id="ele">
  点我
</div>
<script>
  var ele = document.getElementById('ele');

  ele.onclick = function(e) {
    alert(e); // undefined
    alert(window.event);
  }
</script>
运行案例 点击 "运行案例" 可查看在线运行效果

图片描述

以下代码在 IE8 中,第一个 alert 将会返回 undefined,第二个才会是事件对象。

部分事件属性也不同,如标准中的 target 属性,在早期 IE 下需要用 srcElement 替代。

建议对兼容性相关内容做个了解即可,框架通常会处理好兼容性问题。

4. 小结

事件对象包含了事件相关的信息,有事件对象,才能对各个事件做更深层次的交互优化。

前置知识
什么是JavaScript 开发与学习环境准备 调试方案
基础
JavaScript 变量 JavaScript 数据类型 JavaScript if 语句 JavaScript for 语句 JavaScript 算数运算符 JavaScript 比较运算符 JavaScript 逻辑运算符 JavaScript 表达式 JavaScript 函数 JavaScript 对象 JavaScript 字符串 JavaScript 数字 JavaScript 数组 JavaScript switch 语句 JavaScript while 语句 JavaScript break与continue JavaScript with document.cookie
内置对象
JavaScript Function JavaScript Math JavaScript Date JavaScript RegExp JavaScript JSON
JavaScript 与 DOM
什么是DOM DOM和JavaScript的关系 获取和操作 DOM 节点 JavaScript DOM与事件 JavaScript DOM 事件绑定 JavaScript DOM 事件对象 JavaScript DOM 事件流 JavaScript DOM 事件优化 JavaScript DOM 自定义事件
表单处理
使用 JavaScript 校验表单
BOM
BOM window 对象 常用的 BOM 相关对象 BOM 常用属性和方法
AJAX
JavaScript AJAX
进阶知识
JavaScript 异常处理 JavaScript 三元运算符 JavaScript 逗号操作符 JavaScript void JavaScript typeof JavaScript delete JavaScript debugger JavaScript getter &setter JavaScript 原型 JavaScript new操作符和构造函数 JavaScript instanceof JavaScript this JavaScript 严格模式 JavaScript 作用域 JavaScript 闭包 JavaScript 变量提升 JavaScript 对象包装器
常用库
jQuery Lodash moment.js swiper
进阶指南
ECMAScript6 Node.js Babel CSS 预处理器 代码规范 TypeScript Web Components 小程序 Vue / React / Angular JavaScript 关键字
常见疑点与误区
分号问题 对象属性访问问题 this 使用问题 浮点数精度问题 独一无二的 NaN 避免全局污染 控制台观察对象问题 根据环境选择语言特性
扩展
相关资源