事件对象与事件委托

384 阅读5分钟

时间对象

时间对象:用来表示时间的对象

作用:可以得到当前系统时间

在代码中发现了 new 关键字时,一般将这个操作称为实例化

创建一个时间对象并获取时间

获得当前时间

let date = new Date()

获得指定时间

let date = new Date('1994-11-29')

因为时间对象返回的数据我们不能直接使用,所以需要转换为实际开发中常用的格式

1649313255550

实例化

    <h1></h1>
    <script>
        let h1 = document.querySelector('h1')
        setInterval (function repeat(){
            // 实例化一个时间对象
            let date = new Date()
            let year = date.getFullYear(); // 输出当下是什么年份
            let month = date.getMonth();  // 输出月份 0-12
            let date1 = date.getDate();  // 输出几号
            let day = date.getDay();  // 输出星期几 
            let hours = date.getHours();  // 小时
            let minutes = date.getMinutes();  // 分钟
            let seconds = date.getSeconds();  // 秒

            h1.innerText = `${year}${month}${date1} 日 星期${day} ${hours} :${minutes}: ${seconds}`
        }, 1000)
    </script>

时间戳

什么是时间戳

是指1970年01月01日00时00分00秒起至现在的毫秒数,它是一种特殊的计量时间的方式

三种方式获取时间戳

  1. 使用 getTime() 方法
    //   三种方法获取时间戳 方式一
    let date = new Date()
    // 获取时间戳
    console.log(date.getTime()); 

  1. 简写 +new Date()
// 方式二 只要日期对象 可以使用+将整个对象转成时间戳
console.log(+(new Date()) );
  1. 使用 Date.now()
console.log(Date.now());

用来快速生成一个不会重复的数字 * 随机数

无需实例化

但是只能得到当前的时间戳, 而前面两种可以返回指定时间的时间戳

发布微博案例

繁琐版

    <link rel="stylesheet" href="css/weibo.css" />
  </head>

  <body>
    <div class="w">
      <div class="controls">
        <img src="./images copy/tip.png" alt="" /><br />
        <textarea
          placeholder="说点什么吧..."
          id="area"
          cols="30"
          rows="100"
          maxlength="200"
        ></textarea>
        <div>
          <span class="useCount">0</span>
          <span>/</span>
          <span>200</span>
          <button id="send">发布</button>
        </div>
      </div>
      <div class="contentList">
        <ul></ul>
      </div>
    </div>
    <script>
      let dataArr = [
        { uname: '司马懿', imgSrc: './images/9.5/01.jpg' },
        { uname: '女娲', imgSrc: './images/9.5/02.jpg' },
        { uname: '百里守约', imgSrc: './images/9.5/03.jpg' },
        { uname: '亚瑟', imgSrc: './images/9.5/04.jpg' },
        { uname: '虞姬', imgSrc: './images/9.5/05.jpg' },
        { uname: '张良', imgSrc: './images/9.5/06.jpg' },
        { uname: '安其拉', imgSrc: './images/9.5/07.jpg' },
        { uname: '李白', imgSrc: './images/9.5/08.jpg' },
        { uname: '阿珂', imgSrc: './images/9.5/09.jpg' },
        { uname: '墨子', imgSrc: './images/9.5/10.jpg' },
        { uname: '鲁班', imgSrc: './images/9.5/11.jpg' },
        { uname: '嬴政', imgSrc: './images/9.5/12.jpg' },
        { uname: '孙膑', imgSrc: './images/9.5/13.jpg' },
        { uname: '周瑜', imgSrc: './images/9.5/14.jpg' },
        { uname: '老夫子', imgSrc: './images/9.5/15.jpg' },
        { uname: '狄仁杰', imgSrc: './images/9.5/16.jpg' },
        { uname: '扁鹊', imgSrc: './images/9.5/17.jpg' },
        { uname: '马可波罗', imgSrc: './images/9.5/18.jpg' },
        { uname: '露娜', imgSrc: './images/9.5/19.jpg' },
        { uname: '孙悟空', imgSrc: './images/9.5/20.jpg' },
        { uname: '黄忠', imgSrc: './images/9.5/21.jpg' },
        { uname: '百里玄策', imgSrc: './images/9.5/22.jpg' },
      ];

      let useCount = document.querySelector('.useCount')
      let textarea = document.querySelector('textarea')
        // 绑定input事件
        textarea.addEventListener("input",function () {
          useCount.innerText = textarea.value.length
        })
        let send = document.querySelector('#send')
        // 点击发布 留下输入内容
        send.addEventListener('click', function(){
            let uls = document.querySelector('ul')
            let index = Math.round(Math.random() * (dataArr.length - 1));  

            let userpic = document.createElement('img') //图片
            userpic.classList.add('userpic')
            userpic.src = dataArr[index].imgSrc

            let username = document.createElement('span')// 名字
            username.classList.add('username')
            username.innerText =  dataArr[index].uname

            let sendTime = document.createElement('p') //时间
            sendTime.classList.add('send-time')
            sendTime.innerText = `发布于 ${getFormatTime()}`

            let info = document.createElement('div')
            info.classList.add('info')

            let theDel = document.createElement('span')
            theDel.classList.add('the_del')
            theDel.innerText = 'X'

            let li = document.createElement('li')
            // 发布的内容
            let content = document.createElement('div')
            content.classList.add('content')
            content.innerText = textarea.value

            info.append(userpic, username, sendTime)
            li.append(info, content, theDel)
            // 清空文本域内容
            textarea.value = []
            // 清空文字字数为0
            useCount.innerText = 0

            // 发布时间
            function getFormatTime(){
              let date = new Date()
              let year = date.getFullYear();
              let month = date.getMonth();
              let date1 = date.getDate();
              let hours = date.getHours();
              let minutes = date.getMinutes();
              let seconds = date.getSeconds();
              // 数字补0️⃣
              month = month < 10 ? '0' + month : month
              date1 = date1 < 10 ? '0' + date1 : date1
              hours = hours < 10 ? '0' + hours : hours
              minutes = minutes < 10 ? '0' + minutes : minutes
              seconds = seconds < 10 ? '0' + seconds : seconds
              // 返回时间结果
              return `${year}-${month}-${date1} ${hours} :${minutes}: ${seconds}`
            }
            uls.appendChild(li)
        })       
    </script>

简洁版

    <link rel="stylesheet" href="css/weibo.css" />
  </head>

  <body>
    <div class="w">
      <div class="controls">
        <img src="./images copy/tip.png" alt="" /><br />
        <textarea
          placeholder="说点什么吧..."
          id="area"
          cols="30"
          rows="100"
          maxlength="200"
        ></textarea>
        <div>
          <span class="useCount">0</span>
          <span>/</span>
          <span>200</span>
          <button id="send">发布</button>
        </div>
      </div>
      <div class="contentList">
        <ul></ul>
      </div>
    </div>
    <script>
        let dataArr = [
        { uname: '司马懿', imgSrc: './images/9.5/01.jpg' },
        { uname: '女娲', imgSrc: './images/9.5/02.jpg' },
        { uname: '百里守约', imgSrc: './images/9.5/03.jpg' },
        { uname: '亚瑟', imgSrc: './images/9.5/04.jpg' },
        { uname: '虞姬', imgSrc: './images/9.5/05.jpg' },
        { uname: '张良', imgSrc: './images/9.5/06.jpg' },
        { uname: '安其拉', imgSrc: './images/9.5/07.jpg' },
        { uname: '李白', imgSrc: './images/9.5/08.jpg' },
        { uname: '阿珂', imgSrc: './images/9.5/09.jpg' },
        { uname: '墨子', imgSrc: './images/9.5/10.jpg' },
        { uname: '鲁班', imgSrc: './images/9.5/11.jpg' },
        { uname: '嬴政', imgSrc: './images/9.5/12.jpg' },
        { uname: '孙膑', imgSrc: './images/9.5/13.jpg' },
        { uname: '周瑜', imgSrc: './images/9.5/14.jpg' },
        { uname: '老夫子', imgSrc: './images/9.5/15.jpg' },
        { uname: '狄仁杰', imgSrc: './images/9.5/16.jpg' },
        { uname: '扁鹊', imgSrc: './images/9.5/17.jpg' },
        { uname: '马可波罗', imgSrc: './images/9.5/18.jpg' },
        { uname: '露娜', imgSrc: './images/9.5/19.jpg' },
        { uname: '孙悟空', imgSrc: './images/9.5/20.jpg' },
        { uname: '黄忠', imgSrc: './images/9.5/21.jpg' },
        { uname: '百里玄策', imgSrc: './images/9.5/22.jpg' },
      ];

        let useCount = document.querySelector('.useCount')
        let area = document.querySelector('#area')
        let send = document.querySelector('#send')
        let uls = document.querySelector('ul')

        send.addEventListener('click', function(){
            let user = getUser()
            let liHtml = `
            <li>
            <div class="info">
              <img class="userpic" src="${user.imgSrc}" /> 
              <span class="username">${user.uname}</span>
              <p class="send-time">${getFormatTime()}</p>
            </div>
            <div class="content">${area.value}</div>
            <span class="the_del">X</span>
          </li>
            `;
            // 每点击一次 在旧标签的基础上拼接多一个标签
            uls.innerHTML += liHtml
            // 清空文本域内容
            area.value = ''
            // 清空文字字数为0
            useCount.innerText = 0
        })
        
        
        // 绑定input事件
        area.addEventListener("input",function () {
          useCount.innerText = area.value.length
        })
        function getUser(){
            let index = Math.round(Math.random() * (dataArr.length - 1));  
            let user = dataArr[index]
            return user
        }
        // 发布时间
        function getFormatTime(){
          let date = new Date()
          let year = date.getFullYear();
          let month = date.getMonth();
          let date1 = date.getDate();
          let hours = date.getHours();
          let minutes = date.getMinutes();
          let seconds = date.getSeconds();
          // 数字补0️⃣
          month = month < 10 ? '0' + month : month
          date1 = date1 < 10 ? '0' + date1 : date1
          hours = hours < 10 ? '0' + hours : hours
          minutes = minutes < 10 ? '0' + minutes : minutes
          seconds = seconds < 10 ? '0' + seconds : seconds
          // 返回时间结果
          return `${year}-${month}-${date1} ${hours} :${minutes}: ${seconds}`
        }
      </script>

事件对象

1、获取事件对象

事件对象也是个对象,这个对象里有事件触发时的相关信息

例如:鼠标点击事件中,事件对象就存了鼠标点在哪个位置等信息

如何获取

在事件绑定的回调函数的第一个参数就是事件对象

一般命名为 eventeve

1649686209534

2、事件对象常用属性

部分常用属性

type

获取当前的事件类型

clientX / clientY

获取光标相对于浏览器可见窗口左上角的位置

offsetX / offsetY

获取光标相对于当前DOM元素左上角的位置

key

用户按下的键盘键的值 现在不提倡使用keyCode

跟随鼠标案例

需求:一张图片一直跟着鼠标移动

分析:

①:鼠标在页面中移动,用到 mousemove 事件

②:不断把鼠标在页面中的坐标位置给图片left和top值即可

    <style>
        img{
            width: 50px;
            position: fixed;
        }
        body{
            height: 100vh;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div></div>
    <img src="./愤怒的小鸟.png" alt="">
    <script>
        // 获取元素
        const img = document.querySelector('img')
        // mousemove  鼠标移动
        // 设置一个在父元素的鼠标移动事件 函数里用事件对象
        document.body.addEventListener('mousemove', function(event){
            // 设置行内样式 
            // 赋值left的定位是clientX(X坐标)坐标返回的是数字 要加px px用字符串拼接
            img.style.left = event.clientX + 'px' // 例如 坐标85+px = 85px
            // 赋值top的定位是clientY(Y坐标)
            img.style.top = event.clientY + 'px'
        })
        //     // console.log(event.type); // 输出当前的事件类型 少用
        //     console.log(event.clientX, event.clientY); // 返回鼠标的位置 参照物是页面的左上角
        //     // console.log(event.offsetX, event.offsetY); // 返回鼠标的坐标 参照物是被点击的元素的左上角
    </script>

按下回车发布微博案例

需求:按下回车键盘,可以发布信息

分析:

①:用到按下键盘事件 keydown 或者 keyup 都可以

②:如果用户按下的是回车键盘,则发布信息

③:按下键盘发布新闻,其实和点击发布按钮效果一致 send.click()

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
    />
    <title>06-微博发布.html</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
    </style>
  </head>
  <body>
    <a href="http://www.baidu.com"></a>
    <textarea id="area"></textarea>
    <button>发布</button>
    <ul></ul>
    <script>
      /* 
      步骤
      1 给发布按钮 绑定点击事件
        1 获取文本域的内容 
        2 拼接到一个新创建的li标签中
        3 把新创建的li标签插入到ul中

      2 给文本域 绑定键盘按下事件

        按下键盘之后  先判断当下按下的是不是回车  也去执行点击按钮的工作 即可 
       */
      const btn = document.querySelector('button');
      const area = document.querySelector('#area');
      const ul = document.querySelector('ul');

      btn.addEventListener('click', function (event) {
        // 判断一下当前的文本域的内容 是不是空字符串
        if (area.value.trim() === '') {
          console.log('返回不再往下执行');
          return;
        }

        // area.value
        const li = document.createElement('li');
        li.innerText = area.value;
        ul.appendChild(li);
      });

      area.addEventListener('keydown', function (event) {
        // 判断按键是不是回车键
        if (event.key === 'Enter') {
          // console.log("执行和按钮一样的功能");

          // 给btn按钮绑定过点击事件,点击事件也是可以主动触发
          btn.click(); // 你点击了一下按钮

          // 解决按下回车 文本换行的效果
          // 文本域的默认的行为
          // 处理标签的默认行为
          // return false
          event.preventDefault(); // 阻止浏览器标签的默认行为  阻止a标签默认跳转行为
        }
      });

      document.querySelector('a').addEventListener('click', function (e) {
        e.preventDefault(); // 阻止a标签的默认 跳转行为
      });
    </script>
  </body>
</html>

事件流

1、事件流和两个阶段说明

事件流指的是事件完整执行过程中的流动路径

1649767381929

说明:假设页面里有个div,当触发事件时,会经历两个阶段,分别是捕获阶段、冒泡阶段

简单来说:捕获阶段是 从父到子 冒泡阶段是从子到父

2、事件捕获和事件冒泡

事件冒泡概念:

当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发。这一过程被称为事件冒泡

简单理解:当一个元素触发事件后,会依次向上调用所有父级元素的同名事件

事件冒泡是默认存在的

事件捕获概念:

从DOM的根元素开始去执行对应的事件 (从外到里)

事件捕获需要写对应代码才能看到效果 代码:

dom元素.addEventListener('事件类型', 事件处理函数, 是否使用捕获机制)

说明:

addEventListener第三个参数传入true代表是捕获阶段触发(很少使用)

若传入false代表冒泡阶段触发,默认就是false

若是用 L0 事件监听,则只有冒泡阶段,没有捕获

3、阻止事件流动

因为默认就有冒泡模式的存在,所以容易导致事件影响到父级元素

若想把事件就限制在当前元素内,就需要阻止事件流动

阻止事件流动需要拿到事件对象

语法:

事件对象.stopPropagation()

此方法可以阻断事件流动传播,不光在冒泡阶段有效,捕获阶段也有效

鼠标经过事件:

mouseover 和 mouseout 会有冒泡效果

mouseenter 和 mouseleave 没有冒泡效果(推荐)

阻止默认行为,比如链接点击不跳转,表单域的不提交

语法:

event.preventDefault()

两种注册事件的区别:

传统on注册(L0)

同一个对象,后面注册的事件会覆盖前面注册(同一个事件)

直接使用null覆盖偶就可以实现事件的解绑

都是冒泡阶段执行的

事件监听注册(L2)

语法:

addEventListener(事件类型, 事件处理函数, 是否使用捕获)

后面注册的事件不会覆盖前面注册的事件(同一个事件)

可以通过第三个参数去确定是在冒泡或者捕获阶段执行

必须使用removeEventListener(事件类型, 事件处理函数, 获取捕获或者冒泡阶段)

匿名函数无法被解绑

综合演示案例

    <p>1
        <div class="a">
            爷爷
            <div class="b">
                爸爸
                <div class="c">
                    儿子
                </div>
            </div>
        </div>
    </p>
    <script>
        const diva = document.querySelector('.a')
        const divb = document.querySelector('.b')
        const divc = document.querySelector('.c')
        const p = document.querySelector('p')

        diva.addEventListener('click', function(){
            console.log(diva);
            p.innerText = +p.innerText + 1
            // 点击diva p标签变颜色
            p.style.backgroundColor = 'blue'

        })
        divb.addEventListener('click', function(e){
            console.log(divb);
            // 点击一次 p的数字加10
            p.innerText = +p.innerText + 10
            e.stopPropagation()
        })
        divc.addEventListener('click', function(e){
            console.log(divc);
            p.innerText = +p.innerText + 100
            // 阻止事件冒泡
            e.stopPropagation()
        })
         /* 
      事件流动 
      1 给多个父子结构的标签绑定事件, 先点击了子元素, 产生事件流动
      2 事件流动 分成了两个阶段
        1 捕获阶段   父节点 流动到 子节点
        2 冒泡节点   子节点 流动到 父节点   默认
        3 例子:
          人 跳水 
          1 水上 水里面 不断下沉 
        4 事件流动方向 默认是 使用了冒泡 - 点击儿子标签 触发 儿子->父亲->爷爷

      3 我们可以修改触发事件 让它选择使用 捕获阶段还是冒泡阶段(默认)
        addEventListener 可以选择使用冒泡还是捕获
        addEventListener(事件类型,事件处理函数,捕获还是冒泡(默认值 false,可以省略))
        addEventListener("click",function(){}, true )

      4 总结
        1 捕获和 冒泡 特点 了解 
        2 默认情况  冒泡 如果想要修改 可以 addEventListener 第三个参数 传入 true即可
        3 以后的代码开发过程中,还是继续使用默认的 冒泡阶段 
       */
    </script>

阻止标签的默认行为

    <a href="#">baidu</a>
    <form>
        <button>点击</button>
        <input type="button">
    </form>
    <button>点击</button>
    
    <script>
        /* 
        1、a标签的点击跳转
        2、form表单中button点击刷新行为
            1 阻止默认行为 form表单有一个 submit 事件 理解提交表单的触发 点击按钮的时候触发
            2 给button按钮绑定点击事件 也去阻止
            3 给button按钮 添加一个 type="button" 属性 也可以阻止刷新
            4 换成 input标签 type="button" 也一样
            5 把button 移出form表单的区域 

        使用新技术 阻止标签的默认行为 event.preventDefault()
        */
        const a = document.querySelector('a')
        const form = document.querySelector('form')
        const button = document.querySelector('button')

        a.addEventListener('click', function(event){
            console.log('a标签触发了');
            // 阻止a标签的默认行为 不跳转
            event.preventDefault()
        })
        form.addEventListener('submit', function(event){
            // 不让页面再刷新
            event.preventDefault()
        })
    </script>

鼠标右键案例

    <style>
        * {
          margin: 0;
          padding: 0;
          box-sizing: border-box;
        }
        body {
          height: 100vh;
        }
        .menu {
          list-style: none;
          padding: 10px;
          border-radius: 5px;
          border: 1px solid #ccc;
          width: 150px;
          position: fixed;
  
          display: none;
        }
        li {
          height: 40px;
          display: flex;
          align-items: center;
          padding-left: 10px;
          border-bottom: 1px solid #ccc;
        }
        li:hover {
          background-color: skyblue;
          color: #fff;
          cursor: pointer;
        }
        li:last-child {
          border-bottom: none;
        }
      </style>
</head>
<body>
    <ul class="menu">
        <li>添加图标</li>
        <li>切换壁纸</li>
        <li>下载壁纸</li>
        <li>设置</li>
      </ul>
      <script>
        const menu = document.querySelector('.menu');
        // 鼠标右键不要弹出 默认的菜单
  
        // 绑定鼠标右键事件 在 阻止默认行为
        // contextmenu 鼠标右键
        document.body.addEventListener('contextmenu', function (event) {
          event.preventDefault();
          // 坐标
          const left = event.clientX;
          const top = event.clientY;
  
          menu.style.display = 'block';
          menu.style.left = left + 'px';
          menu.style.top = top + 'px';
        });
        // 单击让右键显示出来的样式隐藏
        document.body.addEventListener('click', function () {
          menu.style.display = 'none';
        });
      </script>

事件委托

事件委托是利用事件流的特征解决一些开发需求的知识技巧

总结:

优点:给父级元素加事件(可以提高性能)

原理:事件委托其实是利用事件冒泡的特点, 给父元素添加事件,子元素可以触发

实现:事件对象 .target 可以获得真正触发事件的元素

    <ul>
        <li><a href="#">1</a></li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
    </ul>
    <script>
        // 点击那个li标签 颜色设置为红色
        // 以前获取每一个li标签 数组 遍历他们 按个绑定点击事件
        const uls = document.querySelector('ul')
        const lis = document.querySelectorAll('li')
        // for (let index = 0; index < lis.length; index++) {
        //     lis[index].addEventListener('click', function(){
        //         this.style.backgroundColor = 'aqua'
        //     })
        // }

        // 事件委托
        // 本来是给li标签绑定事件实现业务
        // 把事件绑定写在父元素身上 把li标签应该要做的事情 委托给父元素来做
        uls.addEventListener('click', function(event){
            // event.target 可能是ul标签 也可能是li标签 还有可能是a标签
            // event.target.style.backgroundColor = 'aqua' // 不够完美的方式
            // event.target 当前点击的是那个标签 (点击最深最底层的那个标签即可)
            // console.log(event.target); // 获取到被点击的li标签


            
            // 设置点击li标签vai触发
            // console.log('event.target.nodeName'); // 当前点击的元素标签名 是大写

            if(event.target.nodeName === 'LI'){
                console.log('改变颜色'); 
                event.target.style.backgroundColor = 'red'
            }
        })
    </script>

综合案例

渲染学生信息案例

需求:点击录入按钮,可以增加学生信息

说明: 本次案例主要目的是为了后面Vue做铺垫(数据驱动视图)

效果图

1649774553059

分析

1649774519959

案例

    <h1>新增学员</h1>
    <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>
    <h1>就业榜</h1>
    <table>
      <thead>
        <tr>
          <th>学号</th>
          <th>姓名</th>
          <th>年龄</th>
          <th>性别</th>
          <th>薪资</th>
          <th>就业城市</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
      </tbody>
    </table>
	<script>
        // 1.1 定义数组 负责存放表格要显示的数据
        let arr = [ ];
        const tbody = document.querySelector('tbody');
        // 2  给 录入绑定点击事件
        const add = document.querySelector('.add');
        const uname = document.querySelector('.uname');
        const age = document.querySelector('.age');
        const gender = document.querySelector('.gender');
        const salary = document.querySelector('.salary');
        const city = document.querySelector('.city');
  
        // 1.2 根据数组渲染页面
        renderTableByArr();
  
        // 2  按钮绑定点击事件
        add.addEventListener('click', function () {
          // 2.1 创建一个新的对象 把表单数据都合并到对象中
          const data = {
            // 学号
            id: Date.now(),
            // 姓名
            uname: uname.value,
            // 年龄
            age: age.value,
            // 性别
            gender: gender.value,
            // 薪资
            salary: salary.value,
            // 就业城市
            city: city.value,
          };
  
          // 可以 用断点来测试 上面的代码有没有写错
          // 2.2 给数组插入新的元素
          arr.push(data);
  
          // 2.3 数组发生改变  重新调用渲染页面的函数
          renderTableByArr();
  
          // 2.4 表单数据清空
          uname.value = '';
          age.value = '';
          gender.value = '男';
          salary.value = '';
          city.value = '北京';
        });
  
        // 3 tbody绑定点击事件,同时判断被点击的是不是 del 删除标签
        tbody.addEventListener('click', function (event) {
          // 3.1 判断当前点击的是不是a标签
          if (event.target.nodeName === 'A') {
            // <a data-index="2" href="javascript:" class="del">删除</a>
  
            // 获取到a标签 上存放的 index
            // event.target =  a标签的dom元素
            // console.dir(event.target.dataset.index)
            const index = event.target.dataset.index;
  
            // 3.3 执行数组删除元素
            arr.splice(index,1);
  
            // 3.4 调用根据数组渲染页面的函数 
            renderTableByArr();
          }
        });
        // 根据数组渲染表格
        function renderTableByArr() {
          let html = ``;
          for (let index = 0; index < arr.length; index++) {
            html += `
           <tr>
            <td>${arr[index].id}</td>
            <td>${arr[index].uname}</td>
            <td>${arr[index].age}</td>
            <td>${arr[index].gender}</td>
            <td>${arr[index].salary}</td>
            <td>${arr[index].city}</td>
            <td>
              <a data-index="${index}" href="javascript:" class="del">删除</a>
            </td>
          </tr>
           `;
          }
  
          // 把生成的tr插入到 tbody中
          tbody.innerHTML = html;
        }
      </script>

dataset

    <a href="#">标签</a>
    <div msg="你好" data-index="123"></div>
    <ul>
      <li data-index="0">0</li>
      <li data-index="1">1</li>
      <li data-index="2">2</li>
    </ul>
    <script>
        /* 
        标签的固有属性  天生 自带
        1 a标签的href 
        2 img 标签的src title属性
        3 div class id 
  
        也允许开发者 自己往标签上填写一些属性 - 自定义属性
        h5建议 开发者如果想要在标签上 新增自定义属性的 
        data-xxx
        data-num="100" data-index="200"
        在可以js中通过dom元素
        dom.dataset.xxx
        dom.dataset.num  100 
        dom.dataset.index 200
  
        前端的案例中 
        点击li标签的获取到li标签的下标-位置 index
        数组删除元素  
        arr.splice(要删除的元素的位置 )
         */
         const ul=document.querySelector("ul");
         ul.addEventListener("click",function (event) {
           if(event.target.nodeName==="LI"){
             console.log(event.target.dataset.index);
           }
         })
      </script>