• 【web APIs】快速上手Day03


    Web APIs - 第3天

    进一步学习 事件进阶,实现更多交互的网页特效,结合事件流的特征优化事件执行的效率

    • 掌握阻止事件冒泡的方法
    • 理解事件委托的实现原理

    全选文本框案例

    在这里插入图片描述

    DOCTYPE html>
    
    <html>
    
    <head lang="en">
      <meta charset="UTF-8">
      <title>title>
      <style>
        * {
          margin: 0;
          padding: 0;
        }
    
        table {
          border-collapse: collapse;
          border-spacing: 0;
          border: 1px solid #c0c0c0;
          width: 500px;
          margin: 100px auto;
          text-align: center;
        }
    
        th {
          background-color: #09c;
          font: bold 16px "微软雅黑";
          color: #fff;
          height: 24px;
        }
    
        td {
          border: 1px solid #d0d0d0;
          color: #404060;
          padding: 10px;
        }
    
        .allCheck {
          width: 80px;
        }
      style>
    head>
    
    <body>
      <table>
        <tr>
          <th class="allCheck">
            <input type="checkbox" name="" id="checkAll"> <span class="all">全选span>
          th>
          <th>商品th>
          <th>商家th>
          <th>价格th>
        tr>
        <tr>
          <td>
            <input type="checkbox" name="check" class="ck">
          td>
          <td>小米手机td>
          <td>小米td>
          <td>¥1999td>
        tr>
        <tr>
          <td>
            <input type="checkbox" name="check" class="ck">
          td>
          <td>小米净水器td>
          <td>小米td>
          <td>¥4999td>
        tr>
        <tr>
          <td>
            <input type="checkbox" name="check" class="ck">
          td>
          <td>小米电视td>
          <td>小米td>
          <td>¥5999td>
        tr>
      table>
      <script>
        // 1. 获取大复选框
        const checkAll = document.querySelector('#checkAll')
        // 2. 获取所有的小复选框
        const cks = document.querySelectorAll('.ck')
        // 3. 点击大复选框  注册事件
        checkAll.addEventListener('click', function () {
          // 得到当前大复选框的选中状态
          // console.log(checkAll.checked)  // 得到 是 true 或者是 false
          // 4. 遍历所有的小复选框 让小复选框的checked  =  大复选框的 checked
          for (let i = 0; i < cks.length; i++) {
            cks[i].checked = this.checked
          }
        })
        // 5. 小复选框控制大复选框
    
        for (let i = 0; i < cks.length; i++) {
          // 5.1 给所有的小复选框添加点击事件
          cks[i].addEventListener('click', function () {
            // 判断选中的小复选框个数 是不是等于  总的小复选框个数
            // 一定要写到点击里面,因为每次要获得最新的个数
            // console.log(document.querySelectorAll('.ck:checked').length)
            // console.log(document.querySelectorAll('.ck:checked').length === cks.length)
            checkAll.checked = document.querySelectorAll('.ck:checked').length === cks.length
          })
        }
      script>
    body>
    
    html>
    

    事件流

    事件流是对事件执行过程的描述,了解事件的执行过程有助于加深对事件的理解,提升开发实践中对事件运用的灵活度。

    在这里插入图片描述

    如上图所示,任意事件被触发时总会经历两个阶段:【捕获阶段】和【冒泡阶段】。

    简言之,捕获阶段是【从父到子】的传导过程,冒泡阶段是【从子向父】的传导过程。

    实际工作都是使用事件冒泡为主

    事件捕获

    在这里插入图片描述

    DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Documenttitle>
      <style>
        .father {
          width: 500px;
          height: 500px;
          background-color: pink;
        }
    
        .son {
          width: 200px;
          height: 200px;
          background-color: purple;
        }
      style>
    head>
    
    <body>
      <div class="father">
        <div class="son">div>
      div>
      <script>
        const fa = document.querySelector('.father')
        const son = document.querySelector('.son')
        // 山东  济南  蓝翔   目标(pink老师)  捕获阶段
        //  蓝翔  济南   山东   冒泡阶段
        document.addEventListener('click', function () {
          alert('我是爷爷')
        }, true)
        fa.addEventListener('click', function () {
          alert('我是爸爸')
        }, true)
        son.addEventListener('click', function () {
          alert('我是儿子')
        }, true)
    
      script>
    body>
    
    html>
    

    事件冒泡

    在这里插入图片描述

    DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Documenttitle>
      <style>
        .father {
          width: 500px;
          height: 500px;
          background-color: pink;
        }
    
        .son {
          width: 200px;
          height: 200px;
          background-color: purple;
        }
      style>
    head>
    
    <body>
      <div class="father">
        <div class="son">div>
      div>
      <script>
        const fa = document.querySelector('.father')
        const son = document.querySelector('.son')
        // 山东  济南  蓝翔   目标(pink老师)  捕获阶段
        //  蓝翔  济南   山东   冒泡阶段
        document.addEventListener('click', function () {
          alert('我是爷爷')
        })
        fa.addEventListener('click', function () {
          alert('我是爸爸')
        })
        son.addEventListener('click', function (e) {
          alert('我是儿子')
          // 组织流动传播  事件对象.stopPropagation()
          e.stopPropagation()
        })
    
      script>
    body>
    
    html>
    

    阻止冒泡

    阻止冒泡是指阻断事件的流动,保证事件只在当前元素被执行,而不再去影响到其对应的祖先元素。

    在这里插入图片描述


    在这里插入图片描述

    总结:

    1.阻止冒泡如何做?

    事件对象.stopPropagation()

    2.阻止元素默认行为如何做?

    e.preventDefault()

    解绑事件

    on事件方式解绑

    在这里插入图片描述

    addEventListener方式解绑

    在这里插入图片描述

    注意事项-鼠标经过事件的区别

    鼠标经过事件:

    mouseover 和 mouseout 会有冒泡效果

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

    两种注册事件的区别

    • 传统on注册(L0)

      • 同一个对象,后面注册的事件会覆盖前面注册(同一个事件)
      • 直接使用null覆盖偶就可以实现事件的解绑
      • 都是冒泡阶段执行的
    • 事件监听注册(L2)

      • 语法: addEventListener(事件类型, 事件处理函数, 是否使用捕获)
      • 后面注册的事件不会覆盖前面注册的事件(同一个事件)
      • 可以通过第三个参数去确定是在冒泡或者捕获阶段执行
      • 必须使用removeEventListener(事件类型, 事件处理函数, 获取捕获或者冒泡阶段)
      • 匿名函数无法被解绑

    事件委托

    在这里插入图片描述

    综合案例-tab栏切换改造

    在这里插入图片描述

    DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8" />
      <meta http-equiv="X-UA-Compatible" content="IE=edge" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>tab栏切换title>
      <style>
        * {
          margin: 0;
          padding: 0;
        }
    
        .tab {
          width: 590px;
          height: 340px;
          margin: 20px;
          border: 1px solid #e4e4e4;
        }
    
        .tab-nav {
          width: 100%;
          height: 60px;
          line-height: 60px;
          display: flex;
          justify-content: space-between;
        }
    
        .tab-nav h3 {
          font-size: 24px;
          font-weight: normal;
          margin-left: 20px;
        }
    
        .tab-nav ul {
          list-style: none;
          display: flex;
          justify-content: flex-end;
        }
    
        .tab-nav ul li {
          margin: 0 20px;
          font-size: 14px;
        }
    
        .tab-nav ul li a {
          text-decoration: none;
          border-bottom: 2px solid transparent;
          color: #333;
        }
    
        .tab-nav ul li a.active {
          border-color: #e1251b;
          color: #e1251b;
        }
    
        .tab-content {
          padding: 0 16px;
        }
    
        .tab-content .item {
          display: none;
        }
    
        .tab-content .item.active {
          display: block;
        }
      style>
    head>
    
    <body>
      <div class="tab">
        <div class="tab-nav">
          <h3>每日特价h3>
          <ul>
            <li><a class="active" href="javascript:;" data-id="0">精选a>li>
            <li><a href="javascript:;" data-id="1">美食a>li>
            <li><a href="javascript:;" data-id="2">百货a>li>
            <li><a href="javascript:;" data-id="3">个护a>li>
            <li><a href="javascript:;" data-id="4">预告a>li>
          ul>
        div>
        <div class="tab-content">
          <div class="item active"><img src="./images/tab00.png" alt="" />div>
          <div class="item"><img src="./images/tab01.png" alt="" />div>
          <div class="item"><img src="./images/tab02.png" alt="" />div>
          <div class="item"><img src="./images/tab03.png" alt="" />div>
          <div class="item"><img src="./images/tab04.png" alt="" />div>
        div>
      div>
      <script>
        // 采取事件委托的形式 tab栏切换
        // 1. 获取 ul 父元素 因为 ul只有一个
        const ul = document.querySelector('.tab-nav ul')
        // 获取 5个 item 
        const items = document.querySelectorAll('.tab-content .item')
        // 2. 添加事件
        ul.addEventListener('click', function (e) {
          // console.log(e.target)  // e.target是我们点击的对象
          // 我们只有点击了 a 才会 进行 添加类和删除类操作 
          // console.log(e.target.tagName)  // e.target.tagName 点击那个对象的 标签名
          if (e.target.tagName === 'A') {
            // console.log('我选的是a')
            // 排他思想 ,先移除原来的active  
            document.querySelector('.tab-nav .active').classList.remove('active')
            //当前元素添加 active  是 e.target
            // this 指向ul 不能用this 
            e.target.classList.add('active')
    
            // 下面大盒子模块
            // console.log(e.target.dataset.id)
            const i = +e.target.dataset.id
            // 排他思想 ,先移除原来的active 
            document.querySelector('.tab-content .active').classList.remove('active')
            // 对应的大盒子 添加 active 
            // document.querySelector(`.tab-content .item:nth-child(${i + 1})`).classList.add('active')
            items[i].classList.add('active')
          }
        })
      script>
    body>
    
    html>
    

    其他事件

    页面加载事件

    在这里插入图片描述



    在这里插入图片描述

    总结:

    1. 页面加载事件有哪两个?如何添加?
    • load 事件

      • 监听整个页面资源给 window
    • DOMContentLoaded

      • document

      • 无需等待样式表、图像等完全加载

    元素滚动事件

    在这里插入图片描述

    页面滚动事件-获取位置

    在这里插入图片描述


    在这里插入图片描述

    页面滚动事件-滚动到指定的坐标

    在这里插入图片描述

    页面尺寸事件

    在这里插入图片描述

    页面尺寸事件-获取元素宽高

    在这里插入图片描述

    元素尺寸与位置

    在这里插入图片描述



    在这里插入图片描述

    1. offsetLeft和offsetTop 注意是只读属性

      • 获取元素距离自己定位父级元素的左、上距离
    2. element.getBoundingClientRect()

      • 方法返回元素的大小及其相对于视口的位置

    注意:

    1. offsetWidth和offsetHeight是得到元素什么的宽高?

      • 内容 + padding + border
    2. offsetTop和offsetLeft 得到位置以谁为准?

      • 带有定位的父级

      • 如果都没有则以 文档左上角 为准

    在这里插入图片描述

    综合案例-实现bilibili 点击小滑块移动效果

    在这里插入图片描述

      <script>
        // 1. 事件委托的方法 获取父元素 tabs-list
        const list = document.querySelector('.tabs-list')
        const line = document.querySelector('.line')
        // 2. 注册点击事件
        list.addEventListener('click', function (e) {
          // 只有点击了A 才有触发效果
          if (e.target.tagName === 'A') {
            // console.log(11)
            // 当前元素是谁 ?  e.target
            // 得到当前点击元素的位置
            // console.log(e.target.offsetLeft)
            // line.style.transform = 'translateX(100px)'
            // 把我们点击的a链接盒子的位置  然后移动
            line.style.transform = `translateX(${e.target.offsetLeft}px)`
          }
        })
    
      </script>
    

    综合案例-电梯导航

    在这里插入图片描述

    需求:点击不同的模块,页面可以自动跳转不同的位置

    模块分析:

    ①:页面滚动到对应位置,导航显示,否则隐藏模块

    ②:点击导航对应小模块,页面 会跳到对应大模块位置

    ③:页面滚动到对应位置,电梯导航对应模块自动发生变化

      <script>
        // 第一大模块,页面滑动可以显示和隐藏
        (function () {
          // 获取元素
          const entry = document.querySelector('.xtx_entry')
          const elevator = document.querySelector('.xtx-elevator')
          // 1. 当页面滚动大于 300像素,就显示 电梯导航
          // 2. 给页面添加滚动事件
          window.addEventListener('scroll', function () {
            // 被卷去的头部大于 300 
            const n = document.documentElement.scrollTop
            // if (n >= 300) {
            //   elevator.style.opacity = 1
            // } else {
            //   elevator.style.opacity = 0
            // }
            // 简写
            elevator.style.opacity = n >= entry.offsetTop ? 1 : 0
          })
    
          // 点击返回页面顶部
          const backTop = document.querySelector('#backTop')
          backTop.addEventListener('click', function () {
            // 可读写
            // document.documentElement.scrollTop = 0
            // window.scrollTo(x, y)
            window.scrollTo(0, 0)
          })
        })();
    
        // 第二第三都放到另外一个执行函数里面
        (function () {
          // 2. 点击页面可以滑动 
          const list = document.querySelector('.xtx-elevator-list')
          list.addEventListener('click', function (e) {
            // console.log(11)
            if (e.target.tagName === 'A' && e.target.dataset.name) {
              // 排他思想  
              // 先移除原来的类active 
              // 先获取这个active的对象
              const old = document.querySelector('.xtx-elevator-list .active')
              // console.log(old)
              // 判断 如果原来有active类的对象,就移除类,如果开始就没有对象,就不删除,所以不报错
              if (old) old.classList.remove('active')
              // 当前元素添加 active 
              e.target.classList.add('active')
              // 获得自定义属性  new   topic 
              // console.log(e.target.dataset.name)
              // 根据小盒子的自定义属性值 去选择 对应的大盒子
              // console.log(document.querySelector(`.xtx_goods_${e.target.dataset.name}`).offsetTop)
              // 获得对应大盒子的 offsetTop
              const top = document.querySelector(`.xtx_goods_${e.target.dataset.name}`).offsetTop
              // 让页面滚动到对应的位置
              document.documentElement.scrollTop = top
    
            }
          })
    
    
          // 3. 页面滚动,可以根据大盒子选 小盒子 添加 active 类
          window.addEventListener('scroll', function () {
            //  3.1  先移除类 
            // 先获取这个active的对象
            const old = document.querySelector('.xtx-elevator-list .active')
            // console.log(old)
            // 判断 如果原来有active类的对象,就移除类,如果开始就没有对象,就不删除,所以不报错
            if (old) old.classList.remove('active')
            // 3.2 判断页面当前滑动的位置,选择小盒子
    
            // 获取4个大盒子
            const news = document.querySelector('.xtx_goods_new')
            const popular = document.querySelector('.xtx_goods_popular')
            const brand = document.querySelector('.xtx_goods_brand')
            const topic = document.querySelector('.xtx_goods_topic')
            const n = document.documentElement.scrollTop
            if (n >= news.offsetTop && n < popular.offsetTop) {
              // 选择第一个小盒子
              document.querySelector('[data-name=new]').classList.add('active')
            } else if (n >= popular.offsetTop && n < brand.offsetTop) {
              document.querySelector('[data-name=popular]').classList.add('active')
            } else if (n >= brand.offsetTop && n < topic.offsetTop) {
              document.querySelector('[data-name=brand]').classList.add('active')
            } else if (n >= topic.offsetTop) {
              document.querySelector('[data-name=topic]').classList.add('active')
            }
          })
    
        })();
    
      </script>
    
  • 相关阅读:
    强固型工业电脑在码头智能闸口、OCR(箱号识别)、集装箱卡车车载电脑行业应用
    conda如何激活没有名称的环境
    Mysql 45讲学习笔记(七)行锁
    【C++】C 语言与 C++ 语言的关系 ( C 语言发展 | C 语言缺陷 | C 语言 + 面向对象 + 高级语言特性 | C++ 语言增加内容 | C 语言与 C++ 语言应用场景 )
    二叉搜索树的最近公共祖先likou235、二叉搜索树的插入元素likou701
    [学习笔记]TypeScript查缺补漏(一):类
    MongoDB之MongoDBConnectorBI安装与使用
    html在线商城购物网站制作——基于HTML+CSS+JavaScript(oppo手机商城 6页)
    软件测试面试(三)
    基于vue的tiptap编辑器插件(三)
  • 原文地址:https://blog.csdn.net/m0_49067926/article/details/140101837