WebAPIs-04 (事件对象 / 事件流与事件委托)

- 1.事件注册:

事件源.addEventListener(‘事件类型’,事件处理函数) //不要on, 例如 click 、 mouseenter

- 2.移除事件:

事件源.removeEventListener(‘事件类型’,事件处理函数) /* 细节:移除事件只能移除具名事件,无法移除匿名事件 */

    <script>
        /* 学习目标: 注册事件两种方式
            1.点语法注册:    事件源.事件类型 = 事件处理函数
                * box.onclick = function(){ }
            1.1 点语法移除事件:事件源.事件类型 = null
            
            2.事件源.addEventListener('事件类型',事件处理函数) 
            2.1 移除事件: 事件源.removeEventListener('事件类型',事件处理函数) 

            3.点语法与addEventListener()区别 :
                3.1 点语法不可以注册同名事件,后者会覆盖前者。(变量赋值会先销毁旧值)
                3.2 addEventListener()可以注册同名事件,依次触发
         */

        let box = document.querySelector('#box')
        //1.点语法注册事件: 事件源.事件类型 = 事件处理函数
        box.onclick = function(){
            alert('1-我是点语法注册的事件')
        }
        //1.1 点语法移除事件 : 事件源.事件类型 = null
        box.onclick = null

        //2.addEventListener()
        /**
        * @description: 注册事件
        * @param {string} 事件类型 不要on, 例如 click 、 mouseenter
        * @param {function} 事件处理函数
        * @return: 
        */   
        let fn =  function(){
            alert('1-好好学习')
        }

        /* 
        fn : 变量取值。  函数是一种数据类型,也可以像其他数据类型一样,进行赋值
        fn() : 调用函数,得到函数返回值
         */
        box.addEventListener('click', fn )

        box.addEventListener('click',function(){
            alert('2-天天向上')
        })

        //移除事件 
        /* 细节:移除事件只能移除具名事件,无法移除匿名事件 */
        box.removeEventListener('click',fn)

    
    </script>

- 3.阻止默认事件

1.默认事件(行为) : 在HTML中,有一些标签自带点击事件(a标签 form表单)
2.如何阻止默认事件 : e.preventDefault()
* 阻止默认事件,就可以正常触发我们自己注册的事件

 <body>
    <a href="http://www.baidu.com">跳转到百度</a>
    <form action="">
      <input class="username" type="text" placeholder="请输入账号" />
      <br />
      <input class="password" type="text" placeholder="请输入密码" />
      <br />
      <button class="btn">点我登录</button>
    </form>

    <script>
      /*学习目标: 阻止默认事件(默认行为) 
        1.默认事件(行为) :  在HTML中,有一些标签自带点击事件(a标签 form表单)
        2.如何阻止默认事件 :  e.preventDefault()
            * 阻止默认事件,就可以正常触发我们自己注册的事件 
        */

      let a = document.querySelector('a')
      a.onclick = function (e) {
        //阻止默认事件
        e.preventDefault()

        console.log('我是a标签点击事件')
      }

      //表单中的按钮
      document.querySelector('.btn').onclick = function (e) {
        //阻止表单默认行为
        e.preventDefault()
        let username = document.querySelector('.username')
        let password = document.querySelector('.password')
        console.log(username, password)
        /* 了解:只要是表单中的按钮,点击的时候你的网页就会像a标签href一样默认跳转到其他页面。页面的网址就是表单元素的action属性值 */
      }
    </script>

- 4. 事件对象

1.事件对象 : 存储与事件触发相关的数据
* 当一个事件在触发的时候,浏览器会捕捉事件触发相关的数据(鼠标坐标点、键盘按键),存入一个对象中,称之为事件对象
2.如何获取事件对象 : 给事件处理函数添加一个形参即可 event/ev/e
3.事件对象常用属性 :
2.1 e.pageX/e.pageY : 获取鼠标触发点位置
2.2 e.key : 获取具体按键字符串 ‘Enter’
2.3 e.keyCode : 获取键盘ASCII码
ASCII码 : 键盘每一个按键对应一个数字编码,称之为ASCII码

      /* 
      1.事件对象 : 存储与事件触发相关的数据
        * 当一个事件在触发的时候,浏览器会捕捉事件触发相关的数据(鼠标坐标点、键盘按键),存入一个对象中,称之为事件对象
      2.如何获取事件对象 : 给事件处理函数添加一个形参即可   event/ev/e
      3.事件对象常用属性 :
        3.1 e.pageX/e.pageY : 获取鼠标触发点到页面左上角距离
      */

      let box = document.querySelector('#box')
      box.onclick = function (e) {
        console.log(e)
        console.log(e.pageX, e.pageY)
        console.log('有人点我了')
      }

4.1案例:鼠标跟随移动

   <style>
      img {
        /* 要想修改元素的位置,必须要有定位属性 */
        position: absolute;
        left: 0;
        top: 0;
      }
    </style>
  </head>
  <body>
    <img src="./tianshi.gif" alt="" />
    <script>
      /* 
      1.复习学习过的鼠标事件
        onclick : 鼠标单击
        ondblclick : 鼠标双击
        onmouseover/onmouseout : 鼠标移入移出
        onmouseenter/onmouseleave : 鼠标移入移出
        onmousemove : 鼠标移动
      */

      //1.页面鼠标注册
      window.onmousemove = function (e) {
        console.log(e.pageX, e.pageY)
        //定位 宽高这些都是有单位的, 我们需要自己加上单位
        document.querySelector('img').style.left = e.pageX + 'px'
        document.querySelector('img').style.top = e.pageY + 'px'
      }

4.2键盘事件与获取按键

  <body>
    <input type="text" placeholder="请输入内容" />
    <script>
      /* 
      1.复习键盘事件
        onfocus : 键盘成为输入框焦点
        onblur  : 键盘失去输入框焦点
        oninput : 键盘输入
          * 场景: 实时获取输入框文本
        onkeydown : 键盘按下
          * 场景: 搜索框监听enter键
        onkeyup :   键盘松开

      2.获取键盘按键 : 通过事件对象来获取
        2.1 e.pageX/e.pageY : 获取鼠标触发点位置
        2.2 e.key  : 获取具体按键字符串   'Enter'
        2.3 e.keyCode : 获取键盘ASCII码
          ASCII码 : 键盘每一个按键对应一个数字编码,称之为ASCII码
      */

      let input = document.querySelector('input')
      //键盘按下
      input.onkeydown = function (e) {
        console.log(e)
        //enter键:  if(e.key == 'Enter' )
        console.log(e.key)//获取具体按键字符串
        //enter键:  if(e.keyCode == 13)
        console.log(e.keyCode)//获取键盘ASCII码
        console.log('1-键盘被按下')
      }

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

- 5.事件流与事件委托

5.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>
    <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>
      /* 
      1.事件冒泡 : 当子元素事件被触发的时候,子元素所有的父级元素‘同名事件’会被依次触发
        * 子元素 -> 父元素 -> body -> html -> document -> window
        * 事件冒泡是浏览器特点,一直都存在。 以前没有是因为以前并没有给父级元素注册同名事件
      
      2.事件委托 : 
      */

      //子元素
      document.querySelector('.son').onclick = function(){
        alert('1-我是子元素')
      }

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

      //body
      document.body.onclick = function(){
        alert('3-我是body')
      }
      
      //html
      document.documentElement.onclick = function(){
        alert('4-我是html')
      }

      //document
      document.onclick = function(){
        alert('5-我是document')
      }

      //window
      window.onclick = function(){
        alert('6-我是window')
      }
    </script>
  </body>
</html>

5.2事件委托(重点)

事件委托: 给父元素注册,委托子元素处理 ul.οnclick=fuction(e){
alert(e.target.innerText)
}
e.target : 事件触发源。 真正触发这个事件的子元素
事件委托原理:事件冒泡
事件委托应用场景:
实际开发最多:给动态新增的子元素注册事件
性能优化:如果所有的子元素都需要注册同名事件,只需要给父元素注册

事件委托注意点:
委托事件不能通过this找到子元素.(this指向父元素)
事件委托需要通过什么属性找到子元素: e.target

<!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>
  <ul>
    <li>我是班长1</li>
    <li>我是班长2</li>
    <li>我是班长3</li>
    <li>我是班长4</li>
    <li>我是班长5</li>
    <li>我是班长6</li>
  </ul>

  <script>
    /* 
      1.事件冒泡 : 当子元素事件被触发的时候,子元素所有的父级元素‘同名事件’会被依次触发
        * 子元素 -> 父元素 -> body -> html -> document -> window
        * 事件冒泡是浏览器特点,一直都存在。 以前没有是因为以前并没有给父级元素注册同名事件
    
      2.事件委托 : 给父元素注册事件,委托给子元素处理
        2.1 事件委托原理 :  事件冒泡
        2.2 事件委托注意点 : 不能使用this
            this : 指向父元素
            e.target: 指向真正点击的子元素(事件触发源:触发冒泡的源头)
    */

    //事件委托:给父元素注册,委托给子元素处理
    document.querySelector('ul').onclick = function (e) {
      /*
      this : ul  (事件源:这个事件给谁注册的)
      e.target : 事件触发源。 真正触发这个事件的子元素
      */
      alert(e.target.innerText)
    }

      //需求:给页面每一个li元素注册事件事件

      //1.以前写法: 获取所有li元素数组, 遍历数组给每一个li元素注册
      // //(1)获取li元素
      // let liList = document.querySelectorAll('li')
      // //(2)遍历li元素
      // for (let i = 0; i < liList.length; i++) {
      //   //(3)给每一个li元素注册
      //   liList[i].onclick = function () {
      //     // this : 当前点击的li元素
      //     alert(this.innerText)
      //   }
      // }

      // //如果一个元素是动态新增的,则无法直接注册事件
      // let newLi = document.createElement('li')
      // newLi.innerText = '我是新来的'
      // document.querySelector('ul').appendChild(newLi)
  </script>
</body>

</html>

5.3事件捕获(了解即可)

1.事件捕获 : 当子元素事件被触发的时候,会先从最顶级的父元素一级一级往下触发 * window->document->html->body->父元素->子元素

2.如何注册捕获事件
(1)点语法注册的事件一定是冒泡,无法注册捕获
(2)只有一种语法可以注册捕获事件
元素.addEventListener(‘事件类型’,事件处理函数,true)

3.addEventListener第三个参数是一个布尔类型,默认值是false(冒泡) true(捕获)

5.4事件流与阻止事件流

1.事件流三个阶段e.eventPhase: 给元素和父级元素都注册同名事件
1.1事件捕获
1.2事件目标
1.3事件冒泡

2.阻止事件流动 : 阻止冒泡 + 捕获
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>
      .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>
      /* 
      1.事件冒泡 : 当子元素事件被触发的时候,子元素所有的父级元素‘同名事件’会被依次触发
        * 子元素 -> 父元素 -> body -> html -> document -> window
        * 事件冒泡是浏览器特点,一直都存在。 以前没有是因为以前并没有给父级元素注册同名事件
      
      2.事件捕获 : 当子元素事件被触发的时候,会先从最顶级的父元素一级一级往下触发
        * window->document->html->body->父元素->子元素

      3.如何注册捕获事件
        (1)点语法注册的事件一定是冒泡,无法注册捕获
        (2)只有一种语法可以注册捕获事件
            元素.addEventListener('事件类型',事件处理函数,true)

      4.事件流三个阶段e.eventPhase:  给元素和父级元素都注册同名事件 
        1-事件捕获
        2-事件目标
        3-事件冒泡

      5.阻止事件流动 : 阻止冒泡 + 捕获
        e.stopPropagation()
      */

      //子元素
      //addEventListener第三个参数是一个布尔类型,默认值是false(冒泡)  true(捕获)
      document.querySelector('.son').addEventListener('click',function(e){
        alert('1-我是子元素' + e.eventPhase)
      },false)

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

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

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

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

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

6.额外记录部分

        /*
        Js 所有的BUG分为两种
            1.1.语法错误 :Syntax Error
            2.2.数据错误 :Type Error : 
                Type Error:一般是你某个数据是undefined或者null导致
                null:获取元素选择器写错
                nudefined:
                Reference Error:声明变量和使用不是同一个单词(变量声明)
             原因:Cpu解析代码做两件事: 识别语法,处理(运算和存储)数据
        
        2.不报错:
             主要原因是:js中的引用类型可以动态新增数据
             给自己心理大方向案例:绝壁是单词写错        
        */      

/*
classList.add( newClassName );
添加新的类名,如已经存在,取消添加
classList.contains( oldClassName );
确定元素中是否包含指定的类名,返回值为true 、false;
classList.remove( oldClassName );
移除已经存在的类名;
classList.toggle( className );
如果classList中存在给定的值,删除它,否则,添加它;
classList.replace( oldClassName,newClassName );
*/

// 提交 清空表单
document.querySelector('form').reset()

// 阻止默认事件 如默认跳转
      e.preventDefault()

//阻止事件流动(冒泡 + 捕获)
     e.stopPropagation()

//去除字符串空白 trim( )
//判断输入是否为空
if(textarea.value.trim( ) = '')
//获取当前时间
new Date().toLocaleString( )  

7.案例:DOM综合表格处理

在这里插入图片描述

<!DOCTYPE html>
<html>
  <head lang="en">
    <meta charset="UTF-8" />
    <title></title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }

      a {
        text-decoration: none;
        color: #721c24;
      }
      h1 {
        text-align: center;
        color: #333;
        margin: 20px 0;
      }
      table {
        margin: 0 auto;
        width: 800px;
        border-collapse: collapse;
        color: #004085;
      }
      th {
        padding: 10px;
        background: #cfe5ff;

        font-size: 20px;
        font-weight: 400;
      }
      td,
      th {
        border: 1px solid #b8daff;
      }
      td {
        padding: 10px;
        color: #666;
        text-align: center;
        font-size: 16px;
      }
      tbody tr {
        background: #fff;
      }
      tbody tr:hover {
        background: #e1ecf8;
      }
      .info {
        width: 900px;
        margin: 50px auto;
        text-align: center;
      }
      .info input {
        width: 80px;
        height: 25px;
        outline: none;
        border-radius: 5px;
        border: 1px solid #b8daff;
        padding-left: 5px;
      }
      .info button {
        width: 60px;
        height: 25px;
        background-color: #004085;
        outline: none;
        border: 0;
        color: #fff;
        cursor: pointer;
        border-radius: 5px;
      }
      .info .age {
        width: 50px;
      }
    </style>
  </head>

  <body>
    <h1>新增学员</h1>
    <form action="">
      <div class="info">
        姓名:<input type="text" class="uname" /> 年龄:<input
          type="text"
          class="age"
        />
        性别:
        <select name="gender" id="" class="gender">
          <option value="男"></option>
          <option value="女"></option>
        </select>
        薪资:<input type="text" class="salary" /> 就业城市:<select
          name="city"
          id=""
          class="city"
        >
          <option value="北京">北京</option>
          <option value="上海">上海</option>
          <option value="广州">广州</option>
          <option value="深圳">深圳</option>
          <option value="曹县">曹县</option>
        </select>
        <button class="add">录入</button>
      </div>
    </form>

    <h1>就业榜</h1>
    <table>
      <thead>
        <tr>
          <th>学号</th>
          <th>姓名</th>
          <th>年龄</th>
          <th>性别</th>
          <th>薪资</th>
          <th>就业城市</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <!-- <tr>
          <td>1001</td>
          <td>欧阳霸天</td>
          <td>19</td>
          <td></td>
          <td>15000</td>
          <td>上海</td>
          <td>
            <a href="javascript:" class="delete">删除</a>
          </td>
        </tr> -->
      </tbody>

      <script>
          /* 思路分析
          1.点击录入 :(注意点form表单中的按钮需要阻止默认事件)
            1.1 非空判断 : 姓名、年龄、薪资不能为空
            1.2 新增tr元素
              * (1)创建tr  (2)设置内容  (3)添加到table>tbody
            1.3 清空form表单

          2.点击删除 : 使用事件委托技术
            2.1 点击删除, 删除tr标签 ( 删除按钮的父元素的td, td的父元素是tr)

          3.上移
          4.下移
          */

          //1.获取元素
          let uname = document.querySelector('.uname')
          let age = document.querySelector('.age')
          let gender = document.querySelector('.gender')
          let salary = document.querySelector('.salary')
          let city = document.querySelector('.city')
          let add = document.querySelector('.add')

          //2.1 点击录入
          add.onclick = function(e){
            /* 注意点:form表单元素中的按钮需要阻止默认条件 */
            e.preventDefault()
            //3.1 非空判断 : 姓名、年龄、薪资不能为空
            if( uname.value.trim() == '' || age.value.trim() == '' || salary.value.trim() == ''){
              alert('输入框不能为空')
            }else{
              //3.2 新增元素
              //(1)创建空tr标签
              let tr = document.createElement('tr')
              //(2)设置内容
              tr.innerHTML = `
              <td>1001</td>
              <td>${ uname.value }</td>
              <td>${ age.value }</td>
              <td>${ gender.value }</td>
              <td>${ salary.value }</td>
              <td>${ city.value }</td>
              <td>
                <a href="javascript:" class="up">上移</a>
                <a href="javascript:" class="down">下移</a>
                <a href="javascript:" class="delete">删除</a>
              </td>
              `
              //(3)添加到tbody
              document.querySelector('tbody').appendChild(tr)
            }
            //3.3 表单清空 form.reset()
            document.querySelector('form').reset()
          }


          //2.2 使用事件委托给删除按钮注册点击事件
          document.querySelector('tbody').onclick = function(e){
            //点击tbody任意区域都会触发点击事件, 真正委托的是删除按钮
            let tr =  e.target.parentNode.parentNode
            //3.1 多分支判断到底是哪一个按钮: 删除、上移、下移
            if( e.target.classList.contains('delete') ){
              //(1)删除  
              this.removeChild( tr )
            }else if(  e.target.classList.contains('up') ){
              //(2)上移
              //判断tr是不是第一个儿子
              if( tr.previousElementSibling ){//有哥哥可以上移
                //上移:移到tr哥哥的前面
                this.insertBefore(tr,tr.previousElementSibling)
              }else{
                alert('已经是第一个了')
              }
            }else if( e.target.classList.contains('down') ){
              //(3)下移
              //判断tr是不是最后一个儿子
              if( tr.nextElementSibling ){
                //下移: 移到 弟弟的弟弟的前面
                this.insertBefore( tr, tr.nextElementSibling.nextElementSibling )
              }else{
                alert('已经是最后一个了')
              }
            }
          }
        </script>
    </table>
  </body>
</html>

8.思维导图梳理

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值