2023년 웹 프런트엔드 개발을 위한 JavaScript webAPI (3)

모든 버튼 케이스 선택

아래와 같이 코드 쇼:

<!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>Document</title>
</head>
<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>
<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>¥1999</td>
        </tr>
        <tr>
          <td>
            <input type="checkbox" name="check" class="ck">
          </td>
          <td>小米净水器</td>
          <td>小米</td>
          <td>¥4999</td>
        </tr>
        <tr>
          <td>
            <input type="checkbox" name="check" class="ck">
          </td>
          <td>小米电视</td>
          <td>小米</td>
          <td>¥5999</td>
        </tr>
      </table>
      <script>
        //1.获取一个大的复选框
        const checkAll = document.querySelector('#checkAll')
        //2. 获取所有小的复选框
        const  ck = document.querySelectorAll('.ck')
    // 3. 点击大复选框  注册事件
   
    checkAll.addEventListener('click',function(){
    // 得到当前大复选框的选中状态
      // console.log(checkAll.checked)  // 得到 是 true 或者是 false
      // 4. 遍历所有的小复选框 让小复选框的checked  =  大复选框的 checked
        for(let i=0;i<ck.length;i++){
            ck[i].checked = this.checked
        }

    })
      // 5. 小复选框控制大复选框
 for(let i = 0;i<ck.length;i++){
    
      // 5.1 给所有的小复选框添加点击事件
        ck[i].addEventListener('click',function(){
            
        // 判断选中的小复选框个数 是不是等于  总的小复选框个数
        // 一定要写到点击里面,因为每次要获得最新的个数
        // console.log(document.querySelectorAll('.ck:checked').length)
        // console.log(document.querySelectorAll('.ck:checked').length === cks.length)
            checkAll.checked = document.querySelector('.ck:checked').length===ck.length

        })
 }


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

1. 학습 콘텐츠

고급 이벤트에 대해 자세히 알아보고, 보다 인터랙티브한 웹 페이지 효과를 구현하고, 이벤트 스트림의 특성과 결합하여 이벤트 실행의 효율성을 최적화합니다.
  • 이벤트 버블링 방지 방법 마스터

  • 이벤트 위임의 구현 원리 이해

  1. 이벤트 흐름

  1. 이벤트 위임

  1. 다른 이벤트

  1. 요소 크기 및 위치

  1. 종합사례

2. 이벤트 흐름

  1. 개념:

이벤트 흐름은 이벤트 실행 프로세스에 대한 설명으로, 이벤트 실행 프로세스를 이해하면 이벤트에 대한 이해를 심화하고 개발 실무에서 이벤트 적용의 유연성을 향상시키는 데 도움이 됩니다.

위 그림과 같이 어떤 이벤트가 발생하면 항상 [포획 단계]와 [버블 단계]의 두 단계를 거치게 됩니다.

요컨대 포획 단계는 [아버지에서 아들로] 전도 과정이고, 버블링 단계는 [아들에서 아버지로] 전도 과정이다.

  1. 캡처 및 거품

이벤트 흐름이 무엇인지 이해한 후 이벤트 흐름이 이벤트 실행에 어떤 영향을 미치는지 살펴보겠습니다.

<body>
  <h3>事件流</h3>
  <p>事件流是事件在执行时的底层机制,主要体现在父子盒子之间事件的执行上。</p>
  <div class="outer">
    <div class="inner">
      <div class="child"></div>
    </div>
  </div>
  <script>
    // 获取嵌套的3个节点
    const outer = document.querySelector('.outer');
    const inner = document.querySelector('.inner');
    const child = document.querySelector('.child');
        
    // html 元素添加事件
    document.documentElement.addEventListener('click', function () {
      console.log('html...')
    })
        
    // body 元素添加事件
    document.body.addEventListener('click', function () {
      console.log('body...')
    })

    // 外层的盒子添加事件
    outer.addEventListener('click', function () {
      console.log('outer...')
    })
    
    // 中间的盒子添加事件
    outer.addEventListener('click', function () {
      console.log('inner...')
    })
    
    // 内层的盒子添加事件
    outer.addEventListener('click', function () {
      console.log('child...')
    })
  </script>
</body>

위의 코드를 실행하면 클릭 이벤트가 발생하면 그 상위 요소의 클릭 이벤트도 [연속적으로 트리거]되는 것을 알 수 있는데 왜 그런 걸까요?

이벤트 흐름의 특성과 결합하여 요소의 이벤트가 트리거되면 이벤트가 현재 요소에 도달하기 전에 항상 상위 요소를 통과한 다음 현재 요소에서 상위 요소로 전달된다는 것을 알고 있습니다. 흐름 중 이벤트 이벤트가 트리거됩니다.

또 하나 주목해야 할 세부 사항은 이벤트에 의해 차례로 트리거되는 [실행 시퀀스] 이벤트의 실행 시퀀스는 제어 가능, 즉 캡처 단계 또는 버블링 단계에서 실행될 수 있습니다.

버블링 단계에서 이벤트가 실행되는 경우를 버블링 모드라고 부르며, 자식 박스 이벤트를 먼저 실행한 후 부모 박스 이벤트를 .기본값은 버블링 모드입니다.

캡처 단계에서 이벤트가 실행되면 이를 캡처 모드라고 부르며 부모 상자 이벤트를 먼저 실행한 다음 자식 상자 이벤트를 .

<body>
  <h3>事件流</h3>
  <p>事件流是事件在执行时的底层机制,主要体现在父子盒子之间事件的执行上。</p>
  <div class="outer">
    <div class="inner"></div>
  </div>
  <script>
    // 获取嵌套的3个节点
    const outer = document.querySelector('.outer')
    const inner = document.querySelector('.inner')

    // 外层的盒子
    outer.addEventListener('click', function () {
      console.log('outer...')
    }, true) // true 表示在捕获阶段执行事件
    
    // 中间的盒子
    outer.addEventListener('click', function () {
      console.log('inner...')
    }, true)
  </script>
</body>

결론적으로:

  1. addEventListener의 세 번째 매개변수는 캡처 단계 또는 버블링 단계에서 이벤트가 트리거되는지 여부를 결정합니다.

  1. addEventListener의 세 번째 매개변수는 true로 캡처 단계가 트리거되었음을 나타내고, false는 버블링 단계가 트리거되었음을 나타내며 기본값은 false입니다.

  1. 이벤트 흐름은 상위 요소와 하위 요소의 이벤트 유형이 동일한 경우에만 영향을 미칩니다.

  1. 대부분의 장면은 기본 버블링 모드를 사용합니다(이유 중 하나는 초기 IE가 캡처를 지원하지 않는다는 것입니다)

3. 버블링 방지 ev.stopPropagation()

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

<body>
  <h3>阻止冒泡</h3>
  <p>阻止冒泡是指阻断事件的流动,保证事件只在当前元素被执行,而不再去影响到其对应的祖先元素。</p>
  <div class="outer">
    <div class="inner">
      <div class="child"></div>
    </div>
  </div>
  <script>
    // 获取嵌套的3个节点
    const outer = document.querySelector('.outer')
    const inner = document.querySelector('.inner')
    const child = document.querySelector('.child')

    // 外层的盒子
    outer.addEventListener('click', function () {
      console.log('outer...')
    })

    // 中间的盒子
    inner.addEventListener('click', function (ev) {
      console.log('inner...')

      // 阻止事件冒泡
      ev.stopPropagation()
    })

    // 内层的盒子
    child.addEventListener('click', function (ev) {
      console.log('child...')

      // 借助事件对象,阻止事件向上冒泡
      ev.stopPropagation()
    })
  </script>
</body>

结论: ev.stopPropagation() 方法专门阻止事件冒泡

鼠标经过事件:

mouseover 和 mouseout 会有冒泡效果

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

<!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>Document</title>
  <style>
    .dad {
      width: 400px;
      height: 400px;
      background-color: pink;
    }

    .baby {
      width: 200px;
      height: 200px;
      background-color: purple;
    }
  </style>
</head>

<body>
  <div class="dad">
    <div class="baby"></div>
  </div>
  <script>
    const dad = document.querySelector('.dad')
    const baby = document.querySelector('.baby')
    dad.addEventListener('mouseenter', function () {
      console.log('鼠标经过')
    })
    dad.addEventListener('mouseleave', function () {
      console.log('鼠标离开')
    })
  </script>
</body>

</html>
  1. 解绑事件

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

语法如下:

<!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>Document</title>
</head>

<body>
  <button>点击</button>
  <script>
    const btn = document.querySelector('button')
    btn.onclick = function () {
      alert('点击了')
      // L0 事件移除解绑
      btn.onclick = null
    }

  </script>
</body>

</html>

addEventLiistener方式,必须使用

removeEventListener( 事件类型,事件处理函数,[获取捕获或者 冒泡阶段])

添加代码如下

//定义一个函数
function fn (){
     alert('点击了')
}
//绑定事件
btn.addEventListener('click',fn)
//解绑事件
btn.removeEventListener('click',fn)

注意: 匿名函数无法被解绑

两种注册事件的区别

l 传统on注册(L0)

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

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

Ø 都是冒泡阶段执行的

l 事件监听注册(L2)

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

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

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

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

Ø 匿名函数无法被解绑

案例: 理解事件流,一看就懂

<!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>Document</title>
  <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>

三. 事件委托

事件委托是利用事件流的特征解决一些现实开发需求的知识技巧,主要的作用是提升程序效率。

大量的事件监听是比较耗费性能的,如下代码所示

<script>
  // 假设页面中有 10000 个 button 元素
  const buttons = document.querySelectorAll('table button');

  for(let i = 0; i <= buttons.length; i++) {
    // 为 10000 个 button 元素添加了事件
    buttons.addEventListener('click', function () {
      // 省略具体执行逻辑...
    })
  }
</script>

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

优点: 减少注册次数, 可以提高程序性能

原理: 事件委托其实是利用事件冒泡的特点

==>给父元素注册事件,当我们触发子元素的时候会冒泡到父元素身上,从而触发父元素的事件

实现: 事件对象. target.tagName 可以获得真正触发事件的元素ul. addEventListener( ' click' ,function() { } )执行父级点击事件

const ul = document.querySelector('ul')
ul.addEventListener('click', function (e) {
        //console.dir(e.target)
        if(e.target.tagName === 'LI'){
            this.style.color= 'pink'
            }

} )

事件委托案例:

点击相应的关键词,会显示相应的图片

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

四. 其他事件

页面加载事件

加载外部资源(如图片、外联CSS和JavaScript等)加载完毕时触发的事件

有些时候需要等页面资源全部处理完了做一些事情

l 加载外部资源(如图片、外联CSS和JavaScript等)加载完毕时触发的事件

l 为什么要学?

Ø 有些时候需要等页面资源全部处理完了做一些事情

Ø 老代码喜欢把 script 写在 head 中,这时候直接找 dom 元素找不到

l 事件名:load

l 监听页面所有资源加载完毕:

Ø 给 window 添加 load 事件

事件名:load

监听页面所有资源加载完毕:

window.addEventListener('load', function() {
    // xxxxx
})

l 注意:不光可以监听整个页面资源加载完毕,也可以针对某个资源绑定load事件

  • 当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像等完

  • 全加载

  • l 事件名:DOMContentLoaded

  • l 监听页面DOM加载完毕:

Ø 给 document 添加 DOMContentLoaded 事件

document.addEventListener('DOMContentLoaded', function() {
    // 执行的操作
})

页面滚动事件

l 滚动条在滚动的时候持续触发的事件

l 为什么要学?

Ø 很多网页需要检测用户把页面滚动到某个区域后做一些处理, 比如固定导航栏,比如返回顶部

l 事件名:scroll

l 监听整个页面滚动:

Ø 给 window 或 document 添加 scroll 事件

l 监听某个元素的内部滚动直接给某个元素加即可

window.addEventListener('scroll', function() {
    // xxxxx
})

页面滚动事件-获取位置

l scrollLeft和scrollTop (属性)

Ø 获取被卷去的大小

Ø 获取元素内容往左、往上滚出去看不到的距离

Ø 这两个值是可读写的

l 尽量在scroll事件里面获取被卷去的距离

<!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>Document</title>
  <style>
    body {
      height: 3000px;
    }
  </style>
</head>

<body>
  <script>
    document.documentElement.scrollTop = 800
    window.addEventListener('scroll', function () {
      // 必须写到里面
      const n = document.documentElement.scrollTop
      // 得到是什么数据   数字型 不带单位
      // console.log(n)
    })
  </script>
</body>

</html>

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

l scrollTo() 方法可把内容滚动到指定的坐标

l 语法:

元素.scrollTo(x, y)

l 例如:

//让页面滚动到y轴 1000像素的位置
window.scrollTo(0,1000)

页面尺寸事件

会在窗口尺寸改变的时候触发事件:

window.addEventListener('resize', function() {
    // xxxxx
})

元素尺寸与位置

获取元素的自身宽高、包含元素自身设置的宽高、padding、border

offsetWidth和offsetHeight

获取出来的是数值,方便计算

注意: 获取的是可视宽高, 如果盒子是隐藏的,获取的结果是0

五. 综合案例

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

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

模块分析:

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

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

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

资源地址免费获取: 2023年web前端开发之JavaScriptwebAPI(三).rar-Javascript文档类资源-CSDN文库

추천

출처blog.csdn.net/qq_60870118/article/details/129638949