Javascript之事件流和事件委托

186 阅读3分钟

事件

事件的定义

事件的定义:实现交互功能

事件三要素:

  • 事件源 : 什么元素
  • 事件类型 : 什么时刻
  • 事件处理函数 : 做什么事

注册事件

注册事件 : 给元素添加交互

常规语法:事件源.事件类型 = 事件处理函数

    • 特点:不能注册‘同名事件’, 否则会覆盖 拓展语法 : 事件源.addEventListener('事件类型',事件处理函数)
    • 特点:可以注册‘同名事件’,依次触发 示例代码如下:
<!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>

    <div id="box" style="width: 100px;height: 100px;background-color: red"></div>

    <script>
     

        let box = document.querySelector('#box')
        
        //1.点语法
        // box.onclick = function(){
        //     alert(11111)
        // }

        //2.addEventListener()

        /**
        * @description: 给元素注册同名事件
        * @param {string} 事件类型  不要on
        * @param {function} 事件处理函数
        * @return: 
        */
        box.addEventListener('click',function(){
            alert('1-假如生活欺骗了你,请不要悲伤')
        })

        box.addEventListener('click',function(){
            alert('2-因为它明天还会继续欺骗你')
        })


    </script>

</body>
</html>

事件原理及注意点

(1)事件处理函数在注册的时候不会执行. (函数在声明的时候不会执行)

(2)事件处理函数只有两种情况可以执行

  • 第一种: 用户主动触发交互, 浏览器会捕捉交互,底层会自动帮我们调用对象的方法
  • 第二种: 手动调用对象事件处理函数 (3)注册事件移除 点语法移除事件, 赋值null;另外一种通过removeEventListener移除

示例代码如下:

<!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>

    <div id="box" style="width: 100px;height: 100px;background-color: red"></div>

    <script>
`     `
        let box = document.querySelector('#box')
        //1.点语法
        box.onclick = function(){
            alert(11111)
        }
        //1.1 点语法移除事件, 赋值null
        box.onclick = null

        //2.addEventListener()
        /**
        * @description: 给元素注册同名事件
        * @param {string} 事件类型  不要on
        * @param {function} 事件处理函数
        * @return: 
        */
        box.addEventListener('click',function(){
            alert('1-假如生活欺骗了你,请不要悲伤')
        })

        let fn = function(){
            alert('2-因为它明天还会继续欺骗你')
        }

        /* 
        fn    :    取出函数堆地址 (函数也是一种数据类型,也可以像变量一样赋值)
        fn()  :    调用函数
        */
        box.addEventListener('click', fn )


        //移除事件 : 参数与addEventListener一致
        /* 注意点: 只能移除具名函数, 无法移除匿名函数 */
        box.removeEventListener('click', fn )


    </script>

</body>
</html>

事件对象

事件对象的作用

事件对象 : 是存储与事件相关的对象。

  • 当用户触发事件的时候,浏览器会自动捕捉触发时(鼠标坐标和键盘按键)的信息,存入对象中。这个对象称之为事件对象。

如何获取事件对象

如何获取事件对象 : 给事件处理函数添加形参 event ev e

事件对象常用属性

事件对象常用属性 :

  • e.pageX / e.pageY : 获取鼠标触发点到页面左上角距离
  • e.key 获取按键字符串 ‘Enter’ 'Tab'
  • e.keyCode 获取按键ASCII码 13
  • e.preventDefalt() 阻止form和a默认事件
  • e.stopPropagation() 阻止事件流

示例代码如下:

<!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>
      body {
        width: 3000px;
        height: 3000px;
      }
      #box {
        position: absolute;
        left: 50px;
        top: 50px;
      }
    </style>
  </head>
  <body>
    <div id="box" style="width: 200px;height: 200px;background-color: red"></div>
    <script>
      document.querySelector('#box').onclick = function(e){
        console.log( e.pageX,e.pageY)
      }
    </script>
  </body>
</html>

事件类型

鼠标事件

示例代码如下:

<body>
    <div class="box" style="width: 100px;height: 100px;background-color: pink" ></div>
    <script>
     //获取元素
       let box = document.querySelector('.box')

       //1. 鼠标单击事件: box在点击的时候,背景颜色变红
       box.onclick = function(){
         //事件处理函数
         box.style.backgroundColor = 'red'
       }

       //点击box,浏览器会自动帮你执行这行代码
      //  box.onclick()

      //2. 鼠标双击事件
      box.ondblclick = function(){
        box.style.width = '200px'
      }

      //3. 鼠标移入
      box.onmouseenter = function(){
        box.style.backgroundColor = 'purple'
      }

      //4. 鼠标移出
      box.onmouseleave = function(){
        box.style.backgroundColor = 'hotpink'
      }
      
    
       </script>
       
    </body>

键盘事件

示例代码如下:

<!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" placeholder="请输入内容" />

    <script>
      /* 
      1.键盘事件总结
        onfocus : 成为键盘焦点
        onblur  : 失去键盘焦点
        oninput : 键盘输入
          * 实时获取输入内容
        onkeydown : 键盘按下
          * 监听enter键
        onkeyup   : 键盘松开

      2.如何获取用户按键
        e.key :  获取字符串 'Enter'
        e.keyCode : 获取键盘码ASCII码 13
          * 键盘上每一个按键对应一个数字,称之为ASCII码
      */

      document.querySelector('input').onkeydown = function(e){
        console.log(e)
        console.log(e.key,e.keyCode)
        // console.log('1-键盘按下')
        if(e.key == 'Enter'){
          console.log('执行搜索功能');
        }
        // keyCode : enter的ascii码
        if(e.keyCode == 13 ){
          console.log('执行搜索功能')
        }
      }

      document.querySelector('input').onkeyup = function(){
        // console.log('2-键盘松开')
        
      }
    </script>

  </body>
</html>

页面事件

页面滚动: window.onscroll

  • 页面滚动距离 : document.documentElement.scrollTop

页面大小变化 : window.onresize

  • 页面视口宽度 : document.documentElement.clientWidth

网页跟随鼠标移动案例:

<!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>
      img {
        position: absolute;
        left: 0;
        top: 0;
      }
    </style>
  </head>
  <body>
    <img src="./tianshi.gif" alt="" />

    <script>
    

      //网页鼠标移动 :  window.onmousemove
      
      window.onmousemove = function(e){
        console.log(e.pageX,e.pageY)
        /* 注意点:(1)pageX是数字,设置的时候需要拼接px单位 (2)元素移动前提要有定位 */
        document.querySelector('img').style.left = e.pageX + 'px' 
        document.querySelector('img').style.top = e.pageY + 'px' 
      }
    </script>

  </body>
</html>

事件流

事件冒泡

什么是事件冒泡 : 当触发子元素的事件时候,所有的父级元素‘同名事件’会被依次触发

(如果给元素都设置了点击事件,点击子元素的时候父级元素的事件也会触发)

  • 子元素->父元素->body->html->document->window 示例代码如下:
<!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>
      .father {
        width: 300px;
        height: 300px;
        background-color: red;
      }

      .son {
        width: 100px;
        height: 100px;
        background-color: cyan;
      }
    </style>
  </head>
  <body>
    <div class="father">
      <div class="son"></div>
    </div>

    <script>
  

      //子元素
      document.querySelector('.son').onclick = function(e){
        alert('我是蓝色子元素')
        console.log(e);
      }

      //父元素
      document.querySelector('.father').onclick = function(){
        alert('我是红色父元素')
      }

       //body
       document.body.addEventListener('click',function(){
        alert('我是body')
      })

      //html
      document.documentElement.addEventListener('click',function(){
        alert('我是html')
      })

      //document
      document.addEventListener('click',function(){
        alert('我是document')
      })

      //window
      window.addEventListener('click',function(){
        alert('我是window')
      })

      
    </script>
  </body>
</html>

事件捕获

事件捕获 : 当触发子元素的事件时候,先从最顶级父元素,一级一级往里触发

  • 规则: window->document->html->body->父元素->子元素

  • 默认情况下,所有的注册事件都是冒泡事件。 只有唯一一种方式可以注册捕获事件:

  • 元素.addEventListener('事件类型',事件处理函数,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>
      .father {
        width: 300px;
        height: 300px;
        background-color: red;
      }

      .son {
        width: 100px;
        height: 100px;
        background-color: cyan;
      }
    </style>
  </head>
  <body>
    <div class="father">
      <div class="son"></div>
    </div>

    <script>
      
      //子元素
      document.querySelector('.son').addEventListener('click',function(){
        alert('我是蓝色子元素')
      },true)

      //父元素
      document.querySelector('.father').addEventListener('click',function(){
        alert('我是红色父元素')
      },true)

       //body
       document.body.addEventListener('click',function(){
        alert('我是body')
      },true)

      //html
      document.documentElement.addEventListener('click',function(){
        alert('我是html')
      },true)

      //document
      document.addEventListener('click',function(){
        alert('我是document')
      },true)

      //window
      window.addEventListener('click',function(){
        alert('我是window')
      },true)

    </script>
  </body>
</html>

事件流三个阶段

事件流三个阶段: e.eventPhase 1-捕获阶段 2-目标阶段 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>
    <style>
      .father {
        width: 300px;
        height: 300px;
        background-color: red;
      }

      .son {
        width: 100px;
        height: 100px;
        background-color: cyan;
      }
    </style>
  </head>
  <body>
    <div class="father">
      <div class="son"></div>
    </div>

    <script>
     

      //子元素
      // document.querySelector('.son').addEventListener('click',function(e){
      //   alert('我是蓝色子元素' + e.eventPhase )
      // },false)

      //父元素
      document.querySelector('.father').addEventListener('click',function(e){
        alert('我是红色父元素'+ e.eventPhase )
      },false)

       //body
       document.body.addEventListener('click',function(e){
        alert('我是body'+ e.eventPhase )
      },false)

      //html
      document.documentElement.addEventListener('click',function(e){
        alert('我是html'+ e.eventPhase )
      },false)

      //document
      document.addEventListener('click',function(e){
        alert('我是document'+ e.eventPhase )
      },true)

      //window
      window.addEventListener('click',function(e){
        alert('我是window'+ e.eventPhase )
      },true)

    </script>
  </body>
</html>

阻止事件流动

阻止事件流动 : e.stopPropagation()

事件委托

事件委托的定义

事件委托 : 给父元素注册事件, 委托给子元素处理

事件委托的原理

事件委托原理 : 事件冒泡(当触发子元素的事件时候,所有的父级元素‘同名事件’会被依次触发)

事件委托的注意点

事件委托注意点 :

  • 不能使用 this : this指向父元素

  • 需要使用 e.target : 真正点击的子元素(事件触发源)

事件委托的应用

事件委托的应用 : 给动态新增元素注册事件

示例代码如下:

<!DOCTYPE html>
  <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>
    <button class="btn">点我新增一行li元素</button>
    <ul>
      <li>我是元素1</li>
      <li>我是元素2</li>
      <li>我是元素3</li>
      <li>我是元素4</li>
      <li>我是元素5</li>
      <li>我是元素6</li>
    </ul>

    <script>
    
      //需求: 点击页面每一个li元素,自己的颜色修改为红色
    
      document.querySelector('.btn').onclick = function(){
        document.querySelector('ul').innerHTML += `<li>我是动态新增li元素</li>`
      }

      //根据事件冒泡原理,点击任何li元素都会触发ul点击事件,只需要给ul注册即可
      document.querySelector('ul').onclick = function(e){
        /* 
        this : ul
        e.target : 真正点击的子元素
        */
       console.log( this )
       console.log( e.target )
       e.target.style.backgroundColor = 'red'
      }

    </script>
  </body>
</html>