知识总结与项目-API-03

107 阅读6分钟

1、事件对象常用属性

  • e.clientX/clientY 参照视口左上角 获取光标相对于浏览器可见窗口左上角的位置 e.offsetX/offsetY 参照元素左上角的坐标值 获取光标相对于当前DOM元素左上角的位置
  • e.screenX/e.screenY 鼠标单击位置参照屏幕左上角的坐标值
  • keyup 获取的是当前这一次的value keydown 获取的value是上一次的value 现在不提倡使用keyCode
  • e.which键码
  • e.target当前真正触发事件的元素对象
跟随鼠标案例
    <img src="./images/tianshi.gif" alt="" />

    <script>
      let img = document.querySelector('img')

      // 鼠标跟随:你得监听到鼠标的移动:mousemove,绑定为文档 / body
      document.addEventListener('mousemove', function(e) {
        // document.body.addEventListener('mousemove', function() {
        console.log(e.clientX, e.clientY)

        img.style.left = e.clientX - img.offsetWidth / 2 + 'px'
        img.style.top = e.clientY - img.offsetHeight / 2 + 'px'
      })

2、事件流

  • 事件流
    • 过程: 事件捕获 => 事件目标阶段 => 事件冒泡 整个完整的过程就是事件流
    • 实际工作都是使用事件冒泡为主
  • 事件捕获
    • 概念: 从DOM的根元素开始去执行对应的事件 (从外到里)

    • 捕获机制必须使用事件监听的形式注册

      • DOM.addEventListener(事件类型, 事件处理函数, 是否使用捕获机制)

        • 第三个参数为true:捕获阶段触发事件
        • false代表冒泡阶段触发事件-默认值
  • 事件冒泡
    • 概念: 当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发。这一过程被称为事件冒泡

    • 事件冒泡的必要性

      • 如果没有冒泡.给大盒子注册点击事件, 点击的是里面的小盒子,会导致大盒子的点击无法执行

      • 事件委托

        • 自己不注册事件,将对应的事件注册给祖先元素
        • 减少事件的注册,提高效率
        • e.target => 当前点击的那个元素
    • 阻止事件冒泡

        1. 先要明确那一块区域不能冒泡
        1. 需要阻止什么事件传递就给这块区域的最大盒子注册该事件
        1. 在事件处理函数里面接受事件对象, 并添加上e.stopPropagation()
  • 阻止冒泡和默认行为
    • e.stopPropagation()
      • 阻止事件冒泡
    • e.preventDefault()
      • 链接的跳转
      • 表单域跳转
  • 事件注册的两种方式区别
    • 传统on注册
      • 同一个对象,后面注册的事件会覆盖前面注册(同一个事件)
      • 直接使用null覆盖偶就可以实现事件的解绑
      • 都是冒泡阶段执行的
    • 事件监听注册
      • 语法: addEventListener(事件类型, 事件处理函数, 是否使用捕获)

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

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

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

        • 匿名函数无法被解绑
  • mouseover和 mouseenter的区别

3、事件委托

  • 优点

    • 减少事件的注册,只需要注册化父容器
    • 可以为已存在和未来的元素注册事件,注册一次,现在未来通用
  • 原理:

    • 利用冒泡
  • 使用场景:动态的渲染的元素的事件注册使用委托,动态渲染的元素的事件只能使用委托

let box = document.querySelector('.box')
      let button = document.querySelector('button')

      button.addEventListener('click', function() {
        let newdiv = document.createElement('div')
        newdiv.classList.add('other')
        box.appendChild(newdiv)
      })

      // 如果为父容器绑定事件,那么所有的子元素默认情况下都能触发这个事件,不管这个子元素是 已存在,还是将来创建的
      // 这里是复用事件冒泡的原理,为父容器绑定事件,将来所有子元素都会事件冒泡给这个父容器

      // 这种将事件绑定给父容器的做法让子元素也能响应事件--就叫做事件委托
      box.addEventListener('click', function(e) {
        // e.target:获取当前真正触发事件的对象,说白了,当前用户操作那个元素,e.target就是这个元素
        // console.log(e.target.classList.contains('son'))
        // 我们如何判断当前元素是我们需要的元素呢?
        // 1.我们会为元素添加标识,例如为元素添加一个自定义的类样式
        // 2.判断当前元素是否拥有指定的标识,如果有就是我们想要的元素
        if ((e.target.className = 'son')) {
          console.log('单击了son')
        } else if (e.target.classList.contains('sister')) {
          console.log('单击了sister')
        } else if (e.target.classList.contains('other')) {
          console.log('单击了other')
        }
      })

渲染学生信息案例

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

1642838396806

业务拆分

  • 查询(动态渲染)操作第一个完成

    • 静态结构

    • 数据

    • 现在实现方式1:遍历数据,拼接html结构,最终将结果赋值给某个容器

      • innerHTML
    • 方式2:创建元素,设置内容,追加到指定的容器中

      • createElement
      • appendChild
  • 添加

    • 最关键的准备你要添加的数据,我们的核心任务是收集用户信息,准备好完整的数据

      • stuId:

        • 获取数组中最后一个元素对象的stuId值 +1
        • 如果数组为空,stuId 为1001
      • uname:表单元素

      • age: 表单元素

      • gender: 表单元素

      • salary:表单元素

      • city: 表单元素

    • 添加的页面效果是:在表格中多出一行新增的数据

      • 方式1:

        • 根据数据创建一个新行,追加到tbody中
      • 方式2

        • 将生成的数据对象,追加到数组中,重新渲染

          • 追加数据到数组
          • 将渲染过程封装为函数
          • 调用函数
  • 删除

    • 删除一定体现到数据

      • 删除按钮的事件绑定应该要使用委托

      • 删除数组中的指定位置的元素

        • arr.splice(索引,1)
      • 重新渲染

    • 经验

      • 如果一个业务需要某个值才能进行,我们一般有两种方式来处理

        • 如果可以传递参数就传递参数

        • 先存储再获取

          • 存储在那里

            • 如何取值方便来决定
          • 存储什么

            • 基于业务需求
          • 如何获取

  <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>
           // 获取元素
        let tbody = document.querySelector('tbody')
        let add = document.querySelector('.add')
        // 获取表单元素的值-value值
        let unameEle = document.querySelector('.uname')
        let ageEle = document.querySelector('.age')
        let genderEle = document.querySelector('.gender')
        let salaryEle = document.querySelector('.salary')
        let cityEle = document.querySelector('.city')
        //  1. 准备好数据后端的数据
        let arr = [
            {
                stuId: 1001,
                uname: '欧阳霸天',
                age: 19,
                gender: '男',
                salary: '20000',
                city: '上海'
            },
            {
                stuId: 1002,
                uname: '令狐霸天',
                age: 29,
                gender: '男',
                salary: '30000',
                city: '北京'
            },
            {
                stuId: 1003,
                uname: '诸葛霸天',
                age: 39,
                gender: '男',
                salary: '2000',
                city: '北京'
            }
        ]


        // 2.实现动态渲染  静态结构+数据  
        // 遍历数据  拼接字符串 替换数据 填充到指定位置
        function init() {
            let htmlStr = ''
            arr.forEach(function (item, index) {
                // 把要输入的内容拼接到字符串
                htmlStr += `<tr>
                        <td>${index + 1}</td>
                        <td>${item.uname}</td>
                        <td>${item.age}</td>
                        <td>${item.gender}</td>
                        <td>${item.salary}</td>
                        <td>${item.city}</td>
                        <td>
                          <a href="javascript:" class="del" id='${item.stuId}'>删除</a>
                        </td>
                        </ tr>`
            })
            tbody.innerHTML = htmlStr
        }
        init()

        // 实现数据的新增
        // 1.准备好需要新增的数据,添加到数据源
        // 2.渲染
        add.addEventListener('click', function () {
            // 收集数据,生成一个对象
            let obj = {
                // 获取最后一个数据对象stuId+1,如果没有数据就给ID赋值为1001
                stuId: arr.length > 0 ? arr[arr.length - 1].stuId + 1 : 1001,
                uname: unameEle.value,
                age: ageEle.value,
                gender: genderEle.value,
                salary: salaryEle.value,
                city: cityEle.value
            }
            // 将生成的对象添加给数组
            arr.push(obj)
            // 渲染
            init()
        })

        // 实现数据的删除-动态渲染的元素(新增的元素,未来的元素)的事件的绑定需要使用事件委托
        tbody.addEventListener('click', function (e) {
            // e.target当前用户点击的元素
            // 判断是否点击删除处理
            if (e.target.className == 'del') {
                // 获取你想删除的数据id
                let id = e.target.id
                console.log(id);

                // 根据id找到对应的索引
                for (let i = 0; i < arr.length; i++) {
                    // 删除数据
                    if (id == arr[i].stuId{
                        arr.splice(i, 1)
                        init()
                    }
                }
            }
        })

购物车案例

 <div class="car">
      <table>
        <thead>
          <tr>
            <th><input type="checkbox" id="all" />全选</th>
            <th>商品</th>
            <th>单价</th>
            <th>商品数量</th>
            <th>小计</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody id="carBody"></tbody>
      </table>
      <div class="controls clearfix">
        <a href="javascript:" class="del-all">删除所选商品</a>
        <a href="javascript:" class="clear">清理购物车</a>
        <a href="javascript:" class="pay">去结算</a>
        <p>
          已经选中<span id="totalCount">0</span>件商品;总价:<span
            id="totalPrice"
            class="total-price"
            >0¥</span
          >
        </p>
      </div>
    </div>
    <!-- 引入数据文件 -->
    <script src="./data.js"></script>
    <script>
      let carBody = document.querySelector('#carBody')
      // 数据动态渲染: 数据 +结构 : 遍历 + 拼接 + 赋值
      function init() {
        console.log(data)

        let htmlStr = ''
        data.forEach(function(item, index) {
          htmlStr += `<tr>
                        <td>
                          <input class="s_ck" type="checkbox" ${item.state ? 'checked' : '' }/>
                        </td>
                        <td>
                          <img src="${item.img}" />
                          <p>${item.name}</p>
                        </td>
                        <td class="price">${item.price}</td>
                        <td>
                          <div class="count-c clearfix">
                            <button class="reduce"  id='${index}'>-</button>
                        <inputtype="text"value="${item.count}" />
                            <button class="add" id='${index}'>+</button>
                          </div>
                        </td>
                        <td class="total">${item.price * item.count}¥</td>
                        <td>
                          <a href="javascript:" class="del"  id='${
                            item.id
                          }'>删除</a>
                        </td>
                      </tr>`
        })
        carBody.innerHTML = htmlStr
      }
      init()

      // 加减是动态生成的元素,事件绑定需要使用事件委托
      carBody.addEventListener('click', function(e) {
        if (e.target.className == 'add') {
          // 加
          let index = e.target.id
          // 修改数据
          data[index].count++
          // 重新渲染
          init()
        } else if (e.target.className == 'reduce') {
          // 减
          let index = e.target.id
          if (data[index].count == 1) {
            return
          }
          // 修改数据
          data[index].count--
          // 重新渲染
          init()
        } else if (e.target.className == 'del') {
          // 删除
          let id = e.target.id

          // 直接删除
          data = data.filter(function(v) {
            return v.id != id
          })

          init()
        }
      })