关于 JS 事件,你了解多少?

100 阅读5分钟

一、事件对象

什么是事件对象

当触发一个事件以后,对该事件的一些描述信息

比如:

鼠标点击时的坐标

触发键盘事件时按下的那个按键

每一个事件都会有一个对象来描述这些信息,我们就把这个对象叫做事件对象

浏览器给我们一个“黑盒子”,叫做 window.event 就是对事件信息的所有描述

语法:

元素.onclick = function(){
console.log(window.event.X轴的坐标点信息)
console.log(window.event.Y轴的坐标点信息)
}

缺点:这个东西有兼容性问题,在低版本的IE里边能用,但是在高版本 IE和 Chrome里面不好使

所以我们需要换一种使用方式:

就是在一个事件处理函数的形参位置,默认第一个就是事件对象

二、点击事件的光标位置

坐标一定是一个相对的数据

比如:

  • 相对于事件源(就是我们点击的那个元素)
  • 相对于页面
  • 相对于浏览器窗口
<html>
<head>
  <style>
    body{
      height: 5000px;
    }
    div{
      width: 300px;
      height: 300px;
      padding: 20px;
      border: 10px solid #333;
      margin: 50px;
      position: fixed;
      top: 50px;
    }
  </style>
</head>
<body>
  <div></div>
  <script>
      // 0.获取元素
      var box = document.querySelector('div')
    
      box.onclick = function(e){
      // 1.相对于事件源的鼠标坐标点  相对于点击的元素的边框内侧开始计算
      console.log('相对于事件源 X轴', e.offsetX)
      console.log('相对于事件源 Y轴', e.offsetY)

      // 2.相对于页面
      console.log('==========分割线==========')
      console.log('相对于页面 X 轴', e.pageX)
      console.log('相对于页面 Y 轴', e.pageY)

      // 3.相对于浏览器窗口
      console.log('==========分割线==========')
      console.log('相对于浏览器窗口 X 轴', e.clientX)
      console.log('相对于浏览器窗口 Y 轴', e.clientY)
    }
  </script>
</body>

三、获取键盘按键

键盘的每一个按键都有一个自己的编码,我们可以通过 事件对象.keyCode 来获取

<body>
  <input type="text">
  <script>
    // 0. 获取元素
    var inp = document.querySelector('input')

    // inp.onkeyup = function (e) {
    //   console.log('e.keyCode:' + e.keyCode + ';e.key:' + e.key)
    // }

    /**
     * 组合按键 alt / shift / ctrl
    */

    inp.onkeyup = function (e) {
      // console.log(e.ctrlKey)
      // console.log(e.altKey)
      // console.log(e.keyCode) //q===81

      if (e.altKey && e.keyCode === 81) {
        console.log('按下了组合按键 alt + q')
      }
    }
  </script>
</body>

四、onXXX绑定的弊端

<html>
<head>
  <style>
    div {
      width: 200px;
      height: 200px;
      background-color: pink;
    }
  </style>
</head>
<body>
  <div></div>
  <script>
    // 0. 获取元素
    var box = document.querySelector('div')

    // 1. 给box元素添加一个点击事件
    box.onclick = function () {
      console.log('点击事件1,触发了~')
    }

    // 2. 给box元素添加第二个点击事件
    box.onclick = function () {
      console.log('点击事件2,触发了~')
    }

    /**
     * 问题:
     *    我们现在注册事件就是通过 onXXX
     *    只能给元素注册一个事件,如果写了第二个,那么第一个就会被覆盖掉
     * 
     * 解决:
     *    如果想要两个事件全都存在,我们可以使用事件监听的方式去给元素绑定事件
     * 
     *    使用 addEventListener 去给元素通过事件监听的方式
     *    在IE中需要使用 attachEvent (了解即可)
    */
  </script>
</body>
</html>

五、事件监听

addEventListener

  • 语法:元素.addEventListener('事件类型',事件处理函数,第三个形参)

  • 第三个形参先欠着,后续会详细讲解

  • 因为有默认值,我们暂时先不传递第三个形参

  • 注意:这里的事件类型全部都一样,不需要加 on

  • 执行顺序:按照我们注册的顺序执行(也就是代码书写的顺序)

<html>
<head>
  <style>
    div {
      width: 200px;
      height: 200px;
      background-color: pink;
    }
  </style>
</head>
<body>
  <div></div>
  <script>
    // 0. 获取元素
    var box = document.querySelector('div')

    // 元素.addEventListener('事件类型',事件处理函数,第三个形参)
    box.addEventListener('click', function () {
      console.log('绑定的第一个事件')
    })

    box.addEventListener('click', function () {
      console.log('绑定的第二个事件')
    })

    box.addEventListener('click', function () {
      console.log('绑定的第三个事件')
    })
  </script>
</body>
</html>

六、事件传播

假设我们在浏览器内用一个宽高500px的盒子,内部有一个水平垂直都居中的子级盒子,宽高为100px

当我点击在子级盒子上的时候,其实也是点击在了这个父级盒子的身上

这种情况就叫做事件传播

当元素触发一个事件的时候,这个元素的父级节点也会触发相同的事件,父元素的父元素也会触发相同的事件

  • 点击了子级盒子,会触发子级盒子的点击事件

  • 也是点在了父级盒子上,也会触发父级盒子的点击事件

  • 也是点在了 body 上,也会触发 body 的点击事件

  • 也是点在了 html 上,也会触发 html 的点击事件

  • 也是点在了 document 上,也会触发 document 的点击事件

  • 也是点在了 window 上,也会触发 window 的点击事件

  • 页面上任何一个元素触发事件,都会一层一层的最终导致window的相同事件触发

  • 前提是一定得有事件

注意点:

  • 1.只会传播同类事件,如果是点击事件,那么只会触发父级或者父级的父级注册的点击事件,其他类型的事件不会触发

  • 2.只会从点击的元素开始,按照html的结果,逐层向上触发同类型的事件

  • 3.内部元素不管有没有该事件,只要上层元素有该事件,那么上层元素的事件就会触发

七、事件的冒泡与捕获与目标

目标

你点击在哪个元素上,那么这个事件的目标就是这个元素

事件的冒泡与捕获(面试题)

冒泡:就是从目标的事件处理函数开始,依次向上,一直到window的事件处理函数触发

也就是说从下向上的执行事件处理函数

捕获:就是从window的事件处理函数开始,依次向下,一直到目标的事件处理函数触发

也就是说从上向下的执行事件处理函数

按照事件捕获的形式传播
  • addEventListener 第三个参数就是决定当前传播方式为捕获还是冒泡

  • 默认第三个参数为false,代表传播方式为冒泡

  • 如果想按照捕获的形式传播,那么给第三个参数传递一个true

区别:就是在事件的传播中,多个同类型的事件处理函数的执行顺序不同,仅此而已

八、事件委托

事件委托,就是要把我自己做的事,委托给别人帮我完成

因为我们的冒泡机制,点击子元素的时候,也会同步触发父元素的相同事件

所以我们可以把子元素的事件委托给父元素来做

点击子元素的时候,不管子元素有没有点击事件,只要父元素有点击事件,那么就可以触发父元素的点击事件

事件委托的优点
 * 页面上本身没有li,通过代码添加了一些li
 * 这些li是没有点击事件的,每次动态的添加li,还需要重新给li绑定一次点击事件
 * 这时候使用事件委托就比较合适
 * 因为:新加进来的li也是ul的子元素,点击的时候也可以触发 ul的点击事件
 
<body>
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
  </ul>
</body>

九、默认行为

默认行为:不用我们注册,但是自己存在的事情

比如:

  • 鼠标右键单击,会弹出一个菜单

  • 点击a标签后,自己会跳转到页面

这些不需要我们注册就能实现的事情,我们叫做默认事件

阻止默认事件

不希望浏览器执行默认事件时,比如点击a标签,不跳转页面,那么就需要阻止默认事件

两种方式:

1.e.preventDefault() --- 非IE浏览器

2.e.returnValue = false --- IE浏览器(了解即可)

<body>
  <a href="https://www.baidu.com/">点击之后跳转百度</a>
  <script>
    var oA = document.querySelector('a')
    oA.onclick = function (e) {
      console.log('该函数执行,拦截掉了 a 标签的默认行为')
      e.preventDefault()
    }
  </script>
</body>