JavaScript 事件

本文深入解析JavaScript事件机制,涵盖事件类型、事件对象、事件监听、事件传播等核心概念,包括鼠标事件、键盘事件、浏览器事件、表单事件及移动端触摸事件的详细说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JavaScript 事件


事件三要素

  • 事件源:绑定在谁身上的时间(和谁约定好)
  • 事件类型:绑定一个什么事件
  • 事件处理函数:当行为发生的时候,要执行哪一个函数
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    div {
      width: 100px;
      height: 100px;
      background-color: pink;
    }
  </style>
</head>
<body>
  <div></div>

  <script>
    // 1. 获取元素
    var box = document.querySelector('div')

    // 2. 给 div 绑定一个点击事件
    // 事件源: div
    // 事件类型: click(点击行为)
    // 事件处理函数: 准备一个函数, 在点击行为触发的时候执行

    // on 是我们绑定事件的一种方式
    // click 叫做事件类型
    // 当页面打开, 点击在 box 这个元素上的时候, 会执行后面的函数
    box.onclick = function () {
      // 当我执行的时候, box 元素身上的 click 行为被触发了
      console.log('我被点击了')
    }
  </script>
</body>
</html>

常见的事件类型

  • 在 JS 事件类型里面,没有大写字母
一、鼠标事件
  • 都是一些和鼠标相关的事件
  • 注:mouseover 支持冒泡,mouseenter 不支持冒泡
鼠标事件作用
click点击事件
dblclick双击事件
contextmenu右键单击事件
mousedown鼠标按下
mouseup鼠标抬起
mousemove鼠标移动(支持冒泡)
mouseover鼠标移入
mouseout鼠标移出
mouseenter鼠标移入(不支持冒泡)
mouseleave鼠标移出
  • 鼠标事件案例
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    div {
      width: 100px;
      height: 100px;
      background-color: pink;
    }
  </style>
</head>
<body>
  <div id="box">我是一段文本内容</div>
  <script>
  	var box = document.getElementById('box')
  	
    // 点击事件
    box.onclick = function () { console.log('点击事件触发') }

    // 双击事件(每一个双击事件都会触发两个单击行为)
    box.ondblclick = function () { console.log('双击事件触发') }

    // 右键单击事件
    box.oncontextmenu = function () { console.log('鼠标右键单击') }

    // 鼠标按下(当鼠标左键按下去的时候, 不需要抬起来就触发了)
    box.onmousedown = function () { console.log('鼠标按下去了') }

    // 鼠标抬起
    box.onmouseup = function () { console.log('鼠标抬起来了') }

    // 鼠标移动(只要鼠标在元素上移动, 就会触发)
    box.onmousemove = function () { console.log('鼠标在移动呢') }

    // 鼠标移入(当光标从元素外面移动到元素里面的时候)
    box.onmouseover = function () { console.log('鼠标移入元素') }

    // 鼠标移出(当光标从元素里面移动到元素外面的时候)
    box.onmouseout = function () { console.log('鼠标移出元素') }

    // 鼠标移入
    box.onmouseenter = function () { console.log('鼠标移入') }

    // 鼠标移出
    box.onmouseleave = function () { console.log('鼠标移出') }
  </script>
</body>
</html>

二、键盘事件
  • 因为键盘事件,没有办法确定我是在某一个元素上按下的键盘

  • 所以一般来说,我们的键盘事件绑定在 表单元素 或者 document

    • 因为 表单元素 可以被选中,没有焦点
    • 因为 document 表示页面,你在这个页面中和不在这个页面中
键盘事件作用
keydown键盘按下
keyup键盘抬起
keypress键盘按下(按下不放,就会一直触发)
  • 键盘事件案例
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <form action="">
     <input type="text" class="username">
  </form>
  <script>
  	var inp = document.getElementsByClassName('username')[0]
  	
   	// 键盘按下事件
    inp.onkeydown = function () { console.log('键盘按下去了') }

    // 键盘抬起事件
    inp.onkeyup = function () { console.log('键盘抬起来了') }

    // 键盘按下事件
    inp.onkeypress = function () { console.log('键盘按下事件') }
  </script>
</body>
</html>

三、浏览器事件
浏览器事件作用
load加载完毕
unload页面卸载
resize窗口改变
scroll滚动条滚动
四、表单事件
  • 专门给 form、input、textarea、select 标签 使用的
表单事件作用
focus聚焦事件
blur失焦事件
change改变事件
input输入事件 (有文本输入变化就会触发)
submit提交事件 (绑定给 form 标签)
reset重置事件 (绑定给 form 标签)
  • change 是在对比输入之前和输入之后的变化,如果有变化就会触发,没有变化就不会触发

  • submit 和 reset 属于 form 的默认事件

  • 阻止默认事件的提交

	form.onsubmit = function () {
    	console.log('我要提交表单了')
    	return false
    }
  • 表单事件案例
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <form action="">
    <input type="text" class="username">
    <input type="submit" value="提交">
    <input type="reset" value="重置">
  </form>

  <script>
    var inp = document.getElementsByClassName('username')[0]
    var form = document.getElementsByTagName('form')[0]
    
    // 聚焦事件
    inp.onfocus = function () { console.log('文本框聚焦了') }

    // 失焦事件
    inp.onblur = function () { console.log('文本框失焦了') }

    // 改变事件(当用户输入结束的时候, 只要和输入之前的不一样, 就会触发改变行为)
    //   失去焦点的时候表示我输入完毕了
    inp.onchange = function () { console.log('文本框内容改变了') }

    // 输入事件(只要用户在文本框里面输入内容就触发)
    inp.oninput = function () { console.log('你在输入内容') }

    // 表单提交事件(当点击 submit 的时候会触发)
    // 因为以点击 submit 按钮, 就会自动提交表单, 会刷新页面
    // 所以, 其实打印了, 但是我们看不到
    // 我先暂时加一个 return false, 为了看到内容
    // return false 的能力就是不让表单自动提交
    form.onsubmit = function () {
      console.log('我要提交表单了')

      return false
    }
    
    // 表单重置事件
    // 当你点击 reset 按钮的时候会触发, 绑定在 form 标签上
    form.onreset = function () { console.log('表单重置了') }  
  </script>
</body>
</html>

五、移动端触摸事件
移动端触摸事件作用
touchstart触摸开始(手放在屏幕上的时候)
touchmove触摸移动(手在屏幕上移动)
touchend触摸结束(手离开屏幕的时候)
六、其他事件
其他事件类型作用
transitionend过渡动画结束 需要特殊的绑定方式
animationend帧动画结束 需要特殊的绑定方式
selectstart开始框选文本
  • 其他事件案例
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            width: 100px;
            height: 100px;
            background-color: pink;
        }
    </style>
</head>
<body>
    <div id="box">我是一段文本内容</div>
</body>
<script>
    document.onselectstart = function () {
      console.log('你要框选文本框, 请先付费')
      return false
    }
</script>
</html>

事件对象

在每一个事件触发的时候都应该有一些描述性的信息
  • 触发的什么事件
  • 触发在哪一个元素的身上
  • 鼠标事件的时候,光标做点是什么
  • 键盘事件的时候,按下的是哪一个按键
当我们把这些信息放在一个对象里面的时候
  • 我们管这个对象叫做事件对象
  • 事件对象:就是一个保存了本次事件的表述信息的对象数据类型
  • 当你触发事件的时候,浏览器会帮我们记录好这些内容
  • 你只要获取到事件对象,去里面进行查看就可以了
当你绑定好一个事件以后
  • 当用用户触发这个事件的时候
  • 那么浏览器会帮我们把关于这个事件的所有信息都记录下来
  • 给到我们,让我们使用
如何在事件里面获取事件对象
  • 标准浏览器 => 直接在事件处理函数的时候接收一个形参的形式

  • 元素.onclick = function (e) { }
    • e就是一个形参,你可以写 event 或者 ev 或者 e
    • 会在事件触发的时候,由浏览器给我们传递实参
    • 我们直接在事件处理函数里面使用 e 就可以了
    • 得到的就是事件对象(里面包含本次事件的一些描述信息)
    • 所有的时间都有事件对象
  • IE低版本 => 要使用 window.event 来获取

    • 直接在事件处理函数里面使用 window.event 来获取
  • 兼容方式

    • 接收形参
    • 在事件处理函数里面写 e = e || window.event
    • 给形参 e 进行重新赋值
    • 赋值的内容:如果有实参,就使用实参,如果没有,就使用 window.event
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    div {
      width: 100px;
      height: 100px;
      background-color: pink;
    }
  </style>
</head>
<body>
  <div></div>

  <script>
    // 0. 获取元素
    var box = document.getElementsByTagName('div')[0]

    // 1. 绑定事件
    box.onclick = function (e) {
      // e 会在行为触发的时候, 由浏览器传递实参
      // 处理事件对象兼容
      e = e || window.event
      console.log(e)
    }
  </script>
</body>
</html>

事件对象内的信息 - 鼠标事件

学习一些在事件对象内和鼠标事件相关的信息

  • button 属性:决定按下的是鼠标的哪一个按键
  • clientX 和 clientY 属性:相对于浏览器可视窗口左上角的坐标
  • pageX 和 pageY 属性:相对于页面左上角的坐标
  • offsetX 和 offsetY 属性:相对于元素左上角的坐标
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    div {
      width: 100px;
      height: 100px;
      background-color: pink;
      margin: 30px;
    }

    body {
      width: 2000px;
      height: 2000px;
    }
  </style>
</head>
<body>
  <div></div>

  <script>


    // 0. 获取元素
    var box = document.querySelector('div')

    // 坐标点
    box.onclick = function (e) {
      // 处理事件对象兼容
      e = e || window.event

      // 打印看一下几组坐标
      // clientX 和 clientY
      console.log('clientX : ', e.clientX)
      console.log('clientY : ', e.clientY)
      console.log('========================')
      // pageX 和 pageY
      console.log('pageX : ', e.pageX)
      console.log('pageY : ', e.pageY)
      console.log('========================')
      // offsetX 和 offsetY
      console.log('offsetX : ', e.offsetX)
      console.log('offsetY : ', e.offsetY)
      console.log('========================')
    }
  </script>
</body>
</html>

  • 实时显示坐标点案例1
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>

  <h1>
    X 轴坐标点为 : <span class="x">0</span> <br>
    Y 轴坐标点为 : <span class="y">0</span> <br>
  </h1>

  <script>
    // 0. 获取元素, 需要获取两个 span 标签, 需要向里面填充内容
    var spanX = document.querySelector('.x')
    var spanY = document.querySelector('.y')

    // 1. 给 document 绑定鼠标移动事件
    document.onmousemove = function (e) {
      // 处理事件对象兼容
      e = e || window.event

      // 2. 获取鼠标光标点
      var x = e.clientX
      var y = e.clientY

      // 3. 创建一个文本节点
      var textX = document.createTextNode(x)
      var textY = document.createTextNode(y)
      
      // 你每移动一下, 项里面追加一个节点
      // 你移动的多了以后, 里面的节点就越来越多
      // 所以, 我们在每次添加节点之前, 要把你面本身的节点删除掉
      spanX.removeChild(spanX.childNodes[0])
      spanX.appendChild(textX)
      spanY.removeChild(spanY.childNodes[0])
      spanY.appendChild(textY)
    }
  </script>
</body>
</html>
  • 实时显示坐标点案例2
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>

  <h1>
    X 轴坐标点为 : <span class="x">0</span> <br>
    Y 轴坐标点为 : <span class="y">0</span> <br>
  </h1>

  <script>
    // 0. 获取元素, 需要获取两个 span 标签, 需要向里面填充内容
    var spanX = document.querySelector('.x')
    var spanY = document.querySelector('.y')

    // 1. 给 document 绑定鼠标移动事件
    document.onmousemove = function (e) {
      // 处理事件对象兼容
      e = e || window.event

      // 2. 获取鼠标光标点
      var x = e.clientX
      var y = e.clientY

      // // 3. 把拿到的坐标点填充到两个 span 标签里面
      spanX.innerText = x
      spanY.innerText = y
    }
  </script>
</body>
</html>

事件对象内的信息 - 键盘事件

一、你按下的是哪一个按键
  • 我们键盘上每一个按键都有一个自己的编码
  • 我们就是通过事件对象里面的编码来确定你按下的是哪一个按键
  • 获取编码的信息有两个
    • e.keyCode 标准浏览器
    • e.which 火狐 < 20 的版本
    • 兼容处理:var code = e.keyCode || e.which
二、你按下的是不是组合按键
  • 在事件对象里面有四个属性
按键作用
shiftKey判断 shift 按键
ctrlKey判断 ctrl 按键
altKey判断 alt 按键
metaKey (不兼容, IE 没有)判断 win 按键
  • 他们四个的值都是布尔值
    • 默认是 false,表示没有按下
    • 当你按下去的时候,他们会变成 true,表示按下了
  • 我们在判断组合按键的时候
    • 只要多判断一个属性是不是 true 就能知道你按下的是不是组合按键
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <input type="text">

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

    // 1. 绑定一个键盘事件 - 看键盘编码
    inp.onkeydown = function (e) {
      // 处理事件对象兼容
      e = e || window.event
      // 键盘编码的兼容处理
      var code = e.keyCode || e.which

      // 判断你按下的是 回车 按钮
      if (code === 13) {
        alert('您按下的是 回车 按键')
      }
    }
  </script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <input type="text">

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

    // 1. 判断组合按键
    inp.onkeydown = function (e) {
      // 处理事件对象兼容
      e = e || widnow.event
      // 处理键盘编码兼容
      var code = e.keyCode || e.which

      // 判断按下的是组合按键
      if (code === 65 && e.shiftKey === true && e.ctrlKey === true && e.altKey === true) {
        alert('您按下的是 shift + ctrl + alt + a')
        console.log(e)
      } 
    }
  </script>
</body>
</html>

事件监听器

  • 就是我们绑定事件的第二种方式
  • 我们绑定事件一共有两种方式
  • dom0级事件:使用on的方式进行绑定
  • dom2级事件:使用监听器的方式进行绑定
    • 监听器:我们有两种监听器
      • 标准浏览器使用的监听器
      • IE低版本使用的监听器
    • 可以同时绑定多个同类型的事件
一、标准浏览器的事件监听器
  1. 语法:元素.addEventListener(‘事件类型’, 事件处理函数)
  2. 作用:给元素添加一个事件处理函数,当事件触发的时候就有函数执行
二、IE低版本的事件监听器
  1. 语法:元素.attachEvent(‘on事件类型’, 事件处理函数)
  2. 作用:给元素添加一个事件处理函数,当事件触发的时候就有函数执行
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    div {
      width: 200px;
      height: 200px;
      background-color: pink;
    }
  </style>
</head>
<body>
  <div></div>

  <script>
    // 0. 获取元素
    var box = document.getElementsByTagName('div')[0]

    // 1. 标准浏览器使用监听器的方式绑定事件
    box.addEventListener('click', function () {
      console.log('我被点击了')
    })

    // 2. IE 低版本使用事件监听器的方式绑定事件
    // box.attachEvent('onclick', function () {
    //   console.log('我被点击了')
    // })
  </script>
</body>
</html>
三、兼容处理
	// 封装的用事件监听的方式绑定事件
	// ele 元素
	// type	事件类型
	// fn 事件处理函数
    function addEvent(ele,type,fn){
        if(ele.addEventListener){
            ele.addEventListener(type , fn)
        } else {
            ele.attachEvent('on' + type , fn)
        }
    }
    
    addEvent(oDiv,'click',function(){
        console.log(111)
    })

dom0级和dom2级的区别

  • dom0级事件,只能给一种事件绑定一个事件处理函数

    • 因为是 = 赋值,当你给他第二个值的时候,第一个就被覆盖了
  • dom2级事件,可以给一个事件绑定多个事件处理函数,当事件触发的时候都会执行

  • dom2级事件中,addEventListerattachEvent 的区别

    • addEventListener
      • 使用在标准浏览器中
      • 事件类型位置不需要 on
      • 至少两个参数,一个是事件类型,一个是事件处理函数
      • 当你给一个事件注册多个事件处理函数的时候,顺序注册,顺序执行
    • attachEvent
      • 使用在 IE 低版本浏览器中
      • 事件类型位置需要 on
      • 只有两个参数,一个是事件类型,一个是事件处理函数
      • 当你给一个事件注册多个事件处理函数的时候,顺序注册,倒叙执行
  • 案例1:使用 dom0 级事件绑定事件
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    div {
      width: 200px;
      height: 200px;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div> </div>

  <script>
    // 0. 获取元素
    var div = document.getElementsByTagName('div')[0]

    // 1. 使用 dom0 级事件绑定事件
    div.onclick = function () { console.log('我被点击了 一号') }

    // 当这个事件处理函数被赋值给 onclick 的时候, 那么前面的就没有了
    div.onclick = function () { console.log('我被点击了 二号') }
  </script>
</body>
</html>
  • 案例2:在标准浏览器 使用 dom2 级事件绑定事件
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    div {
      width: 200px;
      height: 200px;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div> </div>

  <script>
    // 0. 获取元素
    var div = document.getElementsByTagName('div')[0]

    // 1. 在标准浏览器 使用 dom2 级事件绑定事件
    div.addEventListener('click', function (e) { console.log(e) })
    div.addEventListener('click', function () { console.log('点击了 一号') })
    div.addEventListener('click', function () { console.log('点击了 二号') })
  </script>
</body>
</html>
  • 案例3: 在 IE 低版本浏览器中使用 dom2 级事件绑定事件
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    div {
      width: 200px;
      height: 200px;
      background-color: skyblue;
    }
  </style>
</head>
<body>
  <div> </div>

  <script>
    // 0. 获取元素
    var div = document.getElementsByTagName('div')[0]

    // 2. 在 IE 低版本浏览器中使用 dom2 级事件绑定事件
    div.attachEvent('onclick', function () { console.log(window.event) })
    div.attachEvent('onclick', function () { console.log('IE 一号') })
    div.attachEvent('onclick', function () { console.log('IE 二号') })
  </script>
</body>
</html>

解绑事件

一、dom0级 事件解绑
  • 方法一
    • 元素.on事件类型 = null
    • 因为是赋值的关系,所以当我给一个事件赋值为 null 的时候
      • 当事件触发的时候,就没有事件处理函数执行了
      • 就相当于没有绑定事件是一个道理
  • 方法二
    • 元素.on事件类型 = false
    • 因为是赋值的关系,所以当我给一个事件赋值的时候
      • 当事件触发后,就没有事件处理函数执行了
      • 所以给事件赋值为任意值都可以,只不过我们习惯给他赋值为 null 或者 false
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    div {
      width: 300px;
      height: 300px;
      background-color: pink;
    }
  </style>
</head>
<body>
  <div id="box"></div>
  <script>
    // dom0级 事件解绑
    // 1. 给 div 元素绑定一个 dom0级 事件
    var box = document.querySelector('div')
    box.onclick = function () { console.log('我被点击了') }
    
    // 2. 给 div 元素解绑这个 dom0级 事件
    // 当你给 onclick 赋值为 null 的时候
    // 就把之前赋值的 函数 给覆盖了
    box.onclick = null
  </script>
</body>
</html>
二、dom2级 事件解绑
  • 元素.removeEventListener(‘事件类型’, 要移除的事件处理函数)

    • 使用范围:标准浏览器
  • 元素…detachEvent(‘on事件类型’, 要移除的事件处理函数)

    • 使用范围: IE 低版本浏览器
  • 解绑 dom2级 事件

    • 如果要解绑某一个元素的 dom2级 事件
    • 那么必须在注册的时候就给他单独写成一个函数形式
    • 使用函数名去进行绑定
    • 使用函数名去进行解绑
    • 解除事件监听需要一个个的移除
  • 案例:dom2级 事件解绑(标准浏览器中)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    div {
      width: 300px;
      height: 300px;
      background-color: pink;
    }
  </style>
</head>
<body>
  <div id="box"></div>
  <script>
    // 1. 给 div 绑定一个事件
    var box = document.getElementById('box')
    function a() { console.log('点击 一号') }
    
    // 在第二个参数位置要写函数名, 不能写函数名()
    // 因为 a 表示一个函数地址, a() 表示把这个函数执行了
    // 我们绑定事件, 不是在绑定的时候就执行函数
    // 而是等到事件触发的时候, 在执行函数
    // 所以绑定的时候是给他一个函数地址, 当事件触发的时候, 执行这个地址的函数
    box.addEventListener('click', a)
    box.addEventListener('click', function b() { console.log('点击 二号') })
    
    // 2. 给 div 解绑事件
    //   在绑定的时候, 就把函数单独书写出来, 写成一个独立的函数
    //   在绑定和解绑的时候, 都是用的变量 a
    //   a 保存的是一个函数的地址, 那么此时就可以解绑成功了
    box.removeEventListener('click', a)
  </script>
</body>
</html>
  • 案例:dom2级 事件解绑( IE 低版本浏览器)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    div {
      width: 300px;
      height: 300px;
      background-color: pink;
    }
  </style>
</head>
<body>
  <div id="box"></div>
  <script>
    // dom2级 事件的 IE 低版本解绑
    var box = document.getElementsByTagName('div')[0]
    function a() { console.log('点击 一号') }
    function b() { console.log('点击 二号') }
    
    // 1. 绑定事件
    box.attachEvent('onclick', a)
    box.attachEvent('onclick', b)
   
   // 2. 解绑事件
    box.detachEvent('onclick', a)
    box.detachEvent('onclick', b)
  </script>
</body>
</html>

事件的传播

  • 当你在一个元素上触发行为的时候
    • 你这个行为会按照元素结构父级的顺序,逐层向上传播
    • 相当于在父级身上也触发了这个行为
    • 相当于在父级的父级身上也触发了这个行为
    • 直到 window 为止,都触发了同样的行为
  • 按照我们现在的页面结构来看
    • 当我点击在 inner 元素身上的时候
    • 因为事件的传播,就相当于也点击在了 center 身上
    • 因为事件的传播,就相当于也点击在了 outer 身上
    • 因为事件的传播,就相当于也点击在了 body 身上
    • 因为事件的传播,就相当于也点击在了 html 身上
    • 因为事件的传播,就相当于也点击在了 document 身上
    • 因为事件的传播,就相当于也点击在了 window 身上
  • 假如:现在我给 window 上绑定一个点击事件
    • 那么当我点击在 inner 元素身上的时候,也会触发 window 的点击事件
  • 假如:现在我给 document 上绑定一个点击事件
    • 那么当我点击在 inner元素身上的时候,也会触发 document 的点击事件
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    .outer {
      width: 500px;
      height: 500px;
      background-color: skyblue;
      margin: 30px auto;
      position: relative;
    }
    .center {
      width: 300px;
      height: 300px;
      background-color: pink;
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      margin: auto;
    }
    .inner {
      width: 100px;
      height: 100px;
      background-color: red;
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      margin: auto;
    }
  </style>
</head>
<body>
  <div class="outer">
    <div class="center">
      <div class="inner"></div>
    </div>
  </div>

  <script>
    // 1. 给 window 绑定一个点击事件
    // window 身上的点击事件, 当你在 window 身上触发点击行为的时候, 就会执行事件处理函数
    // 当我点击在 inner 身上的时候, 因为事件的传播, 就相当于在 window 身上触发了点击行为
    // 所以 window 身上的点击事件的事件处理函数就执行了
    window.addEventListener('click', function () { console.log('window 身上的点击事件') })

    // 2. 给 document 绑定一个点击事件
    document.addEventListener('click', function () { console.log('document 身上的点击事件') })

    // 3. 给 html 绑定一个点击事件
    var html = document.querySelector('html')
    html.addEventListener('click', function () { console.log('html 身上的点击事件') })

    // 4. 给 body 绑定一个点击事件
    var body = document.querySelector('body')
    body.addEventListener('click', function () { console.log('body 身上的点击事件') })

    // 5. 给 outer 绑定一个点击事件
    var outer = document.querySelector('.outer')
    outer.addEventListener('click', function () { console.log('outer 身上的点击事件') })

    // 6. 给 center 绑定一个点击事件
    var center = document.querySelector('.center')
    center.addEventListener('click', function () { console.log('center 身上的点击事件') })

    // 7. 给 inner 绑定一个点击事件
    var inner = document.querySelector('.inner')
    inner.addEventListener('click', function () { console.log('inner 身上的点击事件') })
  </script>
</body>
</html>

事件的目标 target

  • 目标:当事件触发,事件处理函数执行的时候,准确触发事件的那个元素

    • 按照现在的页面结构来看
      • 当你点击 inner 的时候,根据事件的传播,会触发 window 身上的点击事件
      • 当你点击 center 的时候,根据事件的传播,会触发 window 身上的点击事件
      • 当你点击 outer 的时候,根据事件的传播,会触发 window 身上的点击事件 …
    • 当 window 的点击事件触发的时候
      • 是因为点击了谁,触发的
      • 是因为点击自己触发的,还是因为点击某一个子元素,通过传播来触发de
    • 准确触发事件的元素,我们叫做 目标
    • 获取事件的目标,在事件对象里面有记录
    • 事件对象就是一个对象数据结构,里面记录了本次事件的信息
  • 事件目标的获取

    • 在事件对象里面通过一个属性来获取
    • target 目标 ------ 标准浏览器
    • srcElement 目标 ------ IE低版本
    • 兼容写法
      • var target = e.target || e.srcElement
  • 事件目标属于事件对象,事件目标是事件对象的一个属性

	// 1. 给 window 绑定一个点击事件
    document.onclick = function (e) {
      // 事件对象的兼容处理
      e = e || window.event
      // 事件目标的兼容处理
      var target = e.target || e.srcElement
      console.log(target)
    }

事件的冒泡和捕获

  • 事件的冒泡和捕获,就是事件触发的顺序

    • 按照现在的页面结构来看,当我点击在 inner 身上的时候
      • 会触发 inner 身上的点击事件
      • 会触发 center 身上的点击事件
      • 会触发 outer 身上的点击事件
      • 会触发 body 身上的点击事件
      • 会触发 html 身上的点击事件
      • 会触发 document 身上的点击事件
      • 会触发 window 身上的点击事件
    • 但是,是先触发自己身上的,后触发 window 身上的
    • 还是,先触发 window 身上的,后触发自己身上的
  • 冒泡:按照从 目标window 的顺序来执行所有的同类型事件

  • 捕获:按照从 window目标 的顺序来执行所有的同类事件

  • 我们怎么让事件按照冒泡或者捕获的顺序执行

    • IE 低版本只能按照冒泡的顺序执行,没有办法设置捕获
    • 标准浏览器,通过 addEventListener 的第三个参数来决定是冒泡还是捕获
      • 第三个参数:是布尔值
        • 默认是 false,表示冒泡
        • 选填是 true,表示捕获(一般很少用)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    .outer {
      width: 500px;
      height: 500px;
      background-color: skyblue;
      margin: 30px auto;
      position: relative;
    }
    .center {
      width: 300px;
      height: 300px;
      background-color: pink;
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      margin: auto;
    }
    .inner {
      width: 100px;
      height: 100px;
      background-color: red;
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      margin: auto;
    }
  </style>
</head>
<body>
  <div class="outer">
    <div class="center">
      <div class="inner"></div>
    </div>
  </div>

  <script>
    // 1. 给 window 绑定一个点击事件
    window.addEventListener('click', function () { console.log('window 身上的点击事件') }, true)

    // 2. 给 document 绑定一个点击事件
    document.addEventListener('click', function () { console.log('document 身上的点击事件') }, true)

    // 3. 给 html 绑定一个点击事件
    var html = document.querySelector('html')
    html.addEventListener('click', function () { console.log('html 身上的点击事件') }, true)

    // 4. 给 body 绑定一个点击事件
    var body = document.querySelector('body')
    body.addEventListener('click', function () { console.log('body 身上的点击事件') }, true)

    // 5. 给 outer 绑定一个点击事件
    var outer = document.querySelector('.outer')
    outer.addEventListener('click', function () { console.log('outer 身上的点击事件') }, true)

    // 6. 给 center 绑定一个点击事件
    var center = document.querySelector('.center')
    center.addEventListener('click', function () { console.log('center 身上的点击事件') }, true)

    // 7. 给 inner 绑定一个点击事件
    var inner = document.querySelector('.inner')
    inner.addEventListener('click', function () { console.log('inner 身上的点击事件') }, true)
  </script>
</body>
</html>


阻止事件传播

  • 例子:
    • 有一个 html 嵌套的结构
    • 点击里面元素的时候,需求是:要做的事情1
    • 点击外面元素的时候,需求是:要做的事情2
    • 现在当我点击里面元素的时候,会把两个事件处理函数都执行了
    • 但是我并不需要,需要的是:点击谁触发谁
  • 分析问题:
    • 当你点击 inner 元素的时候,因为事件的传播
    • 导致你也是点击在了 center 元素身上
    • 所以 center 身上的点击事件也会触发
  • 解决问题
    • 只要我不让事件传播,那么我点击在 inner 身上的时候
    • 因为禁止了事件的传播,那么就相当于没有传播
    • 因此就不会触发 center 身上的点击事件了
  • 兼容处理
    • 如果两个都是属性,我们可以使用 运算符兼容
    • 如果一个属性,一个方法,或者两个都是方法,那么我们就使用 if 条件来写
    • 判断事件对象里面有没有 e.stopPropagation 这个函数,有就执行,没有就用另一个
	if (e.stopPropagation) {
        e.stopPropagetion()
    } else {
        e.cancelBubble = true
    }
  • e.stopPropagation 肯定是一个函数才能 e.stopPropagation()
  • 判断 e.stopPropagation 是不是一个函数就可以
    • 在标准浏览器下它是一个函数,你把它写在 if 条件里面就是 true
    • 在 IE 低版本没有这个东西,它是undefined,你把它写在 if 条件里面就是 false
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .outer{
            width: 500px;
            height: 500px;
            background-color: #f00;
            overflow: hidden;
        }
        .inner{
            width: 200px;
            height: 200px;
            background-color: #ff0;
            margin: 150px;
        }
    </style>
</head>
<body>
    <div class="outer">
        <div class="inner"></div>
    </div>
</body>
<script>   
    var body = document.querySelector('body')
    var outer = document.querySelector('.outer');
    var inner = document.querySelector('.inner');

    body.addEventListener('click',function(){
        console.log('body')
    })
    outer.addEventListener('click',function(){
        console.log('outer')
    })
    inner.addEventListener('click',function(e){
        // 短路赋值
        e = e || window.event;
        console.log('inner');
        // console.log(e)
  
        // 阻止事件冒泡的兼容写法
        if(e.stopPropagation){
            e.stopPropagation();
        } else {
            e.cancelBubble = true;
        }
    })  
</script>
</html>

事件委托

  • 事件委托
    • 把我自己的时间,委托给别人帮我干
    • 我的事件交给别人来干,那么我就不用在自己身上绑定事件了
  • 例子:按照目前的页面结构
    • 我点击每一个 li,都会因为事件冒泡而出发 ul 的点击事件
    • 现在,我只要给 ul 绑定一个点击事件,那么我点击每一个 li 的时候,都会触发
  • 事件委托只能委托给父元素,不能委托给同级元素
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    ul {
      width: 300px;
      height: 500px;
      background-color: skyblue;
      margin: 50px;
    }
    li {
      width: 100px;
      height: 100px;
      background-color: pink;
      margin-bottom: 10px;
    }
  </style>
</head>
<body>
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
  </ul>
  <button>添加 li</button>
 
 <script>
    // 0. 获取 ul 元素
    var ul = document.querySelector('ul')

    // 1. 给  ul 绑定一个点击事件
    // 这个事件会在点击 ul 的时候都会触发
    // 这个事件会在点击 li 的时候, 因为事件冒泡的原因触发

    // 我怎么知道我点击的是 ul 还是 li 触发的
    // 有一个东西叫做事件目标, 就是准确触发事件的元素
    // 当你点击 ul 触发 事件的时候, 事件目标就是 ul
    // 当你点击 li 触发 事件的时候, 事件目标就是 li
    //   你点击哪一个 li, 这个 target 就是哪一个 li
    ul.addEventListener('click', function (e) {
      // 处理事件对象兼容
      e = e || window.event
      // 处理事件目标兼容
      var target = e.target || e.srcElement

      // 判断一下你点击的是 li
      // 元素节点的 nodeName 是大写标签名
      if (target.nodeName === 'LI') {
        console.log('你点击的是 li', target)
      }
    })
  </script>
</body>
</html>

浏览器(事件)的默认行为

一、浏览器默认行为
  • 不需要绑定,浏览器天生自带的一个行为
    • 表单提交:不需要绑定提交事件,只要点击 submit 按钮,会自动提交跳转页面
    • a 超链接:不需要绑定几点事件,只要点击 a 标签就会自动跳转连接
    • 鼠标右键:不需要绑定右键单击事件,只要你单击鼠标右键,会自动出现一个菜单
    • 文本选中:不需要绑定选中事件,只要你框选,就会选中页面中的文本内容
二、阻止浏览器默认行为
  • 标准浏览器:e.preventDefault()

  • IE 低版本:e.returnValue = false

  • 通用的方法:return false

  • 案例1:标准浏览器中阻止浏览器默认行为
	// 绑定一个右键点击事件
    document.oncontextmenu = function (e) {
      // 处理事件对象兼容
      e = e || window.event
      console.log('点击了右键')
      e.preventDefault()
    }
  • 案例2:IE 低版本中阻止浏览器默认行为
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <a href="https://www.baidu.com">点击一下</a>
  <script>
    var a = document.getElementsByTagName('a')[0]
    // 绑定点击事件
    a.onclick = function (e) {
      // 处理事件对象兼容
      e = e || window.event

      console.log('我点击了 a 标签')
      // 只要再这里阻止了默认行为, 那么点击 a 标签就不会跳转连接了
      // IE 低版本使用
      e.returnValue = false
    }
  </script>
</body>
</html>
  • 案例3:通用方法阻止浏览器默认行为
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  我是一段文本内容我是一段文本内容我是一段文本内容我是一段文本内容我是一段文本内容我是一段文本内容我是一段文本内容我是一段文本内容
  我是一段文本内容我是一段文本内容我是一段文本内容我是一段文本内容我是一段文本内容我是一段文本内容我是一段文本内容
  我是一段文本内容我是一段文本内容我是一段文本内容我是一段文本内容我是一段文本内容
  <script>
    // 绑定一个框选文本的事件
    document.onselectstart = function (e) {
      // 处理事件对象兼容
      e = e || window.event
      console.log('请登陆后复制')
      return false
    }
  </script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值