WebAPI(滚动事件,加载事件,元素大小和位置(scroll家族, offset家族,client家族))

579 阅读5分钟

DOM- 网页特效篇

1. 滚动事件

1.1 scroll 概述

当页面进行滚动时触发的事件

image.png 为什么要学?

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

事件名:scroll

监听整个页面滚动:

<script>
    window.addEventListener('scroll',function(){
        
    })
</script>
  • 给 window 或 document 添加 scroll 事件
  • 监听某个元素的内部滚动直接给某个元素加即可

1.2 页面被卷去的头部

  • 如果浏览器的高(或宽)度不足以显示整个页面时,会自动出现滚动条。
  • 当滚动条向下滚动时,页面上面被隐藏掉的高度,我们就称为页面被卷去的头部。
  • 滚动条在滚动时会触发 onscroll事件。

1.3 页面被卷去的头部兼容性解决方案

需要注意的是,页面被卷去的头部,有兼容性问题,因此被卷去的头部通常有如下几种写法:

  1. 声明了 DTD,使用 document.documentElement.scrollTop
  2. 未声明 DTD,使用  document.body.scrollTop
  3. 新方法 window.pageYOffset和 window.pageXOffset,IE9 开始支持
function getScroll() { return { left: window.pageXOffset ||
    document.documentElement.scrollLeft || document.body.scrollLeft||0, top:
    window.pageYOffset || document.documentElement.scrollTop ||
    document.body.scrollTop || 0 }; } 使用的时候 getScroll().left

2. 加载事件

  • 当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像等完全加载
  • 事件名:DOMContentLoaded
  • 监听页面DOM加载完毕:给 document 添加 DOMContentLoaded 事件
  document.addEventListener('DOMContentLoaded',function(){
          
      })

3. 元素大小和位置

3.1 scroll家族

获取宽高:

  • 获取元素的内容总宽高(不包含滚动条)返回值不带单位
  • scrollWidth和scrollHeight

获取位置:

  • 获取元素内容往左、往上滚出去看不到的距离
  • scrollLeft和scrollTop
  • 这两个属性是可以修改的

image.png 开发中,我们经常检测页面滚动的距离,比如页面滚动100像素,就可以显示一个元素,或者固定一个元素

注意事项: document.documentElement HTML 文档返回对象为HTML元素

image.png

案例:页面滚动显示返回顶部按钮

需求:当页面滚动500像素,就显示返回顶部按钮,否则隐藏, 同时点击按钮,则返回顶部

分析:

①:用到页面滚动事件

②:检测页面滚动大于等于100像素,则显示按钮

③:点击按钮,则让页面的scrollTop 重置为 0

image.png

<body>
    <div class="content">123</div>
    <div class="backtop">
        <img src="./images/close2.png" alt="">
        <a href="javascript:;"></a>
    </div>
    <script>
        let backtop = document.querySelector('.backtop');

        window.addEventListener('scroll',function(){
            if(document.documentElement.scrollTop >= 350){
                backtop.style.display = 'block';
            }else{
                backtop.style.display = 'none';
            }
        })


        backtop.addEventListener('click',function(){
            document.documentElement.scrollTop = 0;
        })
    </script>

案例:仿淘宝固定右侧侧边栏

  1. 原先侧边栏是绝对定位

  2. 当页面滚动到一定位置,侧边栏改为固定定位

  3. 页面继续滚动,会让 返回顶部显示出来 案例分析:

  4. 需要用到页面滚动事件 scroll  因为是页面滚动,所以事件源是document

  5. 滚动到某个位置,就是判断页面被卷去的上部值。

  6. 页面被卷去的头部:可以通过window.pageYOffset 获得  如果是被卷去的左侧window.pageXOffset

  7. 注意,元素被卷去的头部是element.scrollTop  , 如果是页面被卷去的头部 则是 window.pageYOffset

  8. 其实这个值 可以通过盒子的 offsetTop可以得到,如果大于等于这个值,就可以让盒子固定定位了

 //1. 获取元素
        var sliderbar = document.querySelector('.slider-bar');
        var banner = document.querySelector('.banner');
        // banner.offestTop 就是被卷去头部的大小 一定要写到滚动的外面
        var bannerTop = banner.offsetTop
            // 当我们侧边栏固定定位之后应该变化的数值
        var sliderbarTop = sliderbar.offsetTop - bannerTop;
        // 获取main 主体元素
        var main = document.querySelector('.main');
        var goBack = document.querySelector('.goBack');
        var mainTop = main.offsetTop;
        // 2. 页面滚动事件 scroll
        document.addEventListener('scroll', function() {
            // console.log(11);
            // window.pageYOffset 页面被卷去的头部
            // console.log(window.pageYOffset);
            // 3 .当我们页面被卷去的头部大于等于了 172 此时 侧边栏就要改为固定定位
            if (window.pageYOffset >= bannerTop) {
                sliderbar.style.position = 'fixed';
                sliderbar.style.top = sliderbarTop + 'px';
            } else {
                sliderbar.style.position = 'absolute';
                sliderbar.style.top = '300px';
            }
            // 4. 当我们页面滚动到main盒子,就显示 goback模块
            if (window.pageYOffset >= mainTop) {
                goBack.style.display = 'block';
            } else {
                goBack.style.display = 'none';
            }

        })

3.2 offset家族

获取宽高:

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

获取位置:

  • 获取元素距离自己定位父级元素的左、上距离
  • offsetLeft和offsetTop 注意是只读属性

image.png

offset 与 style 区别

offse

  • offset 可以得到任意样式表中的样式值
  • offset 系列获得的数值是没有单位的
  • offsetWidth 包含padding+border+width
  • offsetWidth 等属性是只读属性,只能获取不能赋值
  • 所以,我们想要获取元素大小位置,用offset更合适 style
  • style 只能得到行内样式表中的样式值
  • style.width 获得的是带有单位的字符串
  • style.width 获得不包含padding和border 的值
  • style.width 是可读写属性,可以获取也可以赋值
  • 所以,我们想要给元素更改值,则需要用style改变 因为平时我们都是给元素注册触摸事件,所以重点记住 targetTocuhes

仿京东固定头部

<!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>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      .content {
        overflow: hidden;
        width: 1000px;
        height: 3000px;
        background-color: pink;
        margin: 0 auto;
      }

      .backtop {
        display: none;
        width: 50px;
        left: 50%;
        margin: 0 0 0 505px;
        position: fixed;
        bottom: 60px;
        z-index: 100;
      }

      .backtop a {
        height: 50px;
        width: 50px;
        background: url(./images/bg2.png) 0 -600px no-repeat;
        opacity: 0.35;
        overflow: hidden;
        display: block;
        text-indent: -999em;
        cursor: pointer;
      }

      .header {
        position: fixed;
        top: -80px;
        left: 0;
        width: 100%;
        height: 80px;
        background-color: purple;
        text-align: center;
        color: #fff;
        line-height: 80px;
        font-size: 30px;
        transition: all 0.3s;
      }

      .sk {
        width: 300px;
        height: 300px;
        background-color: skyblue;
        margin-top: 500px;
      }
    </style>
  </head>

  <body>
    <div class="header">我是顶部导航栏</div>
    <div class="content">
      <div class="sk">秒杀模块</div>
    </div>
    <div class="backtop">
      <img src="./images/close2.png" alt="" />
      <a href="javascript:;"></a>
    </div>
    <script>
      let header = document.querySelector('.header');
      let sk = document.querySelector('.sk');

      window.addEventListener('scroll', function () {

        if (document.documentElement.scrollTop >= sk.offsetTop) {
          header.style.top = 0;
        } else {
          header.style.top = '-80px';
        }
      });
    </script>
  </body>
</html>

电梯导航案例

<!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>
      * {
        margin: 0;
        padding: 0;
      }

      .aside {
        position: fixed;
        left: 0;
        top: 50%;
        transform: translateY(-50%);
      }

      .item {
        height: 40px;
        line-height: 40px;
        text-align: center;
        padding: 0 10px;
        cursor: pointer;
      }

      .active {
        background-color: red;
        color: #fff;
      }

      .content {
        width: 660px;
        margin: 400px auto;
      }

      .neirong {
        height: 300px;
        margin-bottom: 20px;
        color: #fff;
      }

      .content1 {
        background-color: red;
      }

      .content2 {
        background-color: blue;
      }

      .content3 {
        background-color: orange;
      }

      .content4 {
        background-color: yellowgreen;
      }
    </style>
  </head>

  <body>
    <div class="aside">
      <div class="item active">男装/女装</div>
      <div class="item">儿童服装/游乐园</div>
      <div class="item">电子产品</div>
      <div class="item">电影/美食</div>
    </div>

    <div class="content">
      <div class="neirong content1">男装/女装</div>
      <div class="neirong content2">儿童服装/游乐园</div>
      <div class="neirong content3">电子产品</div>
      <div class="neirong content4">电影/美食</div>
    </div>

    <script>
      let items = document.querySelectorAll('.item');
      let content = document.querySelectorAll('.neirong');
    //   let a = document.querySelector('.active');
      for (let i = 0; i < items.length; i++) {
        items[i].addEventListener('click', function () {
            document.querySelector('.active').classList.remove('active');
            this.classList.add('active');

           document.documentElement.scrollTop =  content[i].offsetTop;
        });
      }
    </script>
  </body>
</html>

3.3 client家族

获取宽高:

  • 获取元素的可见部分宽高(不包含边框,滚动条等)
  • clientWidth和clientHeight

获取位置:

  • 获取左边框和上边框宽度
  • clientLeft和clientTop 注意是只读属性

image.png

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

  • resize

image.png 检测屏幕宽度:

image.png 仿新浪返回顶部

<!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>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        .content {
            width: 1000px;
            height: 3000px;
            background-color: pink;
            margin: 0 auto;
        }

        .backtop {
            display: none;
            width: 50px;
            left: 50%;
            margin: 0 0 0 505px;
            position: fixed;
            bottom: 60px;
            z-index: 100;
        }

        .backtop a {
            height: 50px;
            width: 50px;
            background: url(./images/bg2.png) 0 -600px no-repeat;
            opacity: 0.35;
            overflow: hidden;
            display: block;
            text-indent: -999em;
            cursor: pointer;
        }
    </style>
</head>

<body>
    <div class="content">123</div>
    <div class="backtop">
        <img src="./images/close2.png" alt="">
        <a href="javascript:;"></a>
    </div>
    <script>
        let backtop = document.querySelector('.backtop');

        window.addEventListener('scroll',function(){
            if(document.documentElement.scrollTop >= 350){
                backtop.style.display = 'block';
            }else{
                backtop.style.display = 'none';
            }
        })


        backtop.addEventListener('click',function(){
            document.documentElement.scrollTop = 0;
        })
    </script>
</body>

</html>

综合案例轮播图案例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>QQ音乐轮播图</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      li {
        list-style: none;
      }

      .main {
        width: 700px;
        margin: auto;
        background: #000;
      }

      .slides {
        height: 320px;
        position: relative;
      }

      .slides ul li {
        /* display: none; */
        position: absolute;
        top: 0;
        left: 0;
        opacity: 0;
        /* 这里实现淡入淡出的关键 */
        transition: all 0.3s;
      }

      .slides li.active {
        /* display: block; */
        opacity: 1;
      }

      .slides .extra {
        width: 700px;
        height: 53px;
        line-height: 53px;
        position: absolute;
        bottom: 0px;
        background-color: rgba(0, 0, 0, 0.8);
        z-index: 10;
      }

      .slides .extra h3 {
        width: 82%;
        margin: 0;
        margin-right: 20px;
        padding-left: 20px;
        color: #98e404;
        font-size: 28px;
        float: left;
        font-weight: 500;
        font-family: 'Microsoft Yahei', Tahoma, Geneva;
      }

      .slides .extra a {
        width: 30px;
        height: 29px;
        display: block;
        float: left;
        margin-top: 12px;
        margin-right: 3px;
        background-image: url(./assets/icon_focus_switch.png);
      }

      .slides .extra .prev {
        background-position: 0 0;
      }

      .slides .extra .prev:hover {
        background-position: -30px 0;
      }

      .slides .extra .next {
        background-position: -60px 0;
      }

      .slides .extra .next:hover {
        background-position: -90px 0;
      }

      .indicator {
        padding: 10px 0;
      }

      .indicator ul {
        list-style-type: none;
        margin: 0 0 0 4px;
        padding: 0;
        overflow: hidden;
      }

      .indicator ul li {
        position: relative;
        float: left;
        width: 60px;
        margin: 0 4px 0 5px;
        text-align: center;

        cursor: pointer;
      }

      .indicator li img {
        display: block;
        border: 0;
        text-align: center;
        width: 60px;
      }

      .indicator li .mask {
        width: 60px;
        height: 60px;
        position: absolute;
        top: 0;
        left: 0;
        background-color: rgba(0, 0, 0, 0.4);
      }

      .indicator li .border {
        display: none;
        width: 54px;
        position: absolute;
        bottom: 0;
        left: 0;
        z-index: 20;
        border: 3px solid #98e404;
      }

      /* li里面的mask 和 border 刚开始都是显示的 */
      /* 我们写一个样式css */
      .indicator .active .mask {
        display: none;
      }

      .indicator .active .border {
        display: block;
      }
    </style>
  </head>

  <body>
    <div class="main">
      <div class="slides">
        <ul>
          <li class="active">
            <a href="#">
              <img src="./assets/b_01.jpg" alt="第1张图的描述信息" />
            </a>
          </li>
          <li>
            <a href="#">
              <img src="./assets/b_02.jpg" alt="第2张图的描述信息" />
            </a>
          </li>
          <li>
            <a href="#">
              <img src="./assets/b_03.jpg" alt="第3张图的描述信息" />
            </a>
          </li>
          <li>
            <a href="#">
              <img src="./assets/b_04.jpg" alt="第4张图的描述信息" />
            </a>
          </li>
          <li>
            <a href="#">
              <img src="./assets/b_05.jpg" alt="第5张图的描述信息" />
            </a>
          </li>
          <li>
            <a href="#">
              <img src="./assets/b_06.jpg" alt="第6张图的描述信息" />
            </a>
          </li>
          <li>
            <a href="#">
              <img src="./assets/b_07.jpg" alt="第7张图的描述信息" />
            </a>
          </li>
          <li>
            <a href="#">
              <img src="./assets/b_08.jpg" alt="第8张图的描述信息" />
            </a>
          </li>
          <li>
            <a href="#">
              <img src="./assets/b_09.jpg" alt="第9张图的描述信息" />
            </a>
          </li>
          <li>
            <a href="#">
              <img src="./assets/b_10.jpg" alt="第9张图的描述信息" />
            </a>
          </li>
        </ul>

        <div class="extra">
          <h3>第1张图的描述信息</h3>
          <a class="prev" href="javascript:;"></a>
          <a class="next" href="javascript:;"></a>
        </div>
      </div>
      <div class="indicator">
        <ul>
          <li class="active">
            <img src="assets/s_01.jpg" />
            <span class="mask"></span>
            <span class="border"></span>
          </li>
          <li>
            <img src="assets/s_02.jpg" />
            <span class="mask"></span>
            <span class="border"></span>
          </li>
          <li>
            <img src="assets/s_03.jpg" />
            <span class="mask"></span>
            <span class="border"></span>
          </li>
          <li>
            <img src="assets/s_04.jpg" />
            <span class="mask"></span>
            <span class="border"></span>
          </li>
          <li>
            <img src="assets/s_05.jpg" />
            <span class="mask"></span>
            <span class="border"></span>
          </li>
          <li>
            <img src="assets/s_06.jpg" />
            <span class="mask"></span>
            <span class="border"></span>
          </li>
          <li>
            <img src="assets/s_07.jpg" />
            <span class="mask"></span>
            <span class="border"></span>
          </li>
          <li>
            <img src="assets/s_08.jpg" />
            <span class="mask"></span>
            <span class="border"></span>
          </li>
          <li>
            <img src="assets/s_09.jpg" />
            <span class="mask"></span>
            <span class="border"></span>
          </li>
          <li>
            <img src="assets/s_10.jpg" />
            <span class="mask"></span>
            <span class="border"></span>
          </li>
        </ul>
      </div>
    </div>

    <script>
      let list = document.querySelectorAll('.slides li');
      let h3 = document.querySelector('.extra h3');
      let prev = document.querySelector('.prev');
      let next = document.querySelector('.next');
      let lisb = document.querySelectorAll('.indicator li');

      let index = 0;
      //鼠标经过显示对应的图片
      for (let i = 0; i < lisb.length; i++) {
        lisb[i].addEventListener('mouseenter', function () {
          document.querySelector('.indicator .active').className = '';
          this.className = 'active';

          //显示图片
          document.querySelector('.slides .active').className = '';
          list[i].className = 'active';

          h3.innerHTML = `第${i + 1}张图的描述信息`;
        });
      }
      // 点击右按钮切换下一张
      prev.addEventListener('click', function () {
        index--;
        if (index <= 1) {
          index = 0;
        }
        document.querySelector('.indicator .active').className = '';
        lisb[index].className = 'active';
        h3.innerHTML = `第${index + 1}张图的描述信息`;
        document.querySelector('.slides .active').className = '';
        list[index].className = 'active';
        h3.innerHTML = `第${index + 1}张图的描述信息`;
      });
      // 点击左按钮切换下一张
      next.addEventListener('click', function () {
        index++;
        if (index >= 10) {
          index = 0;
        }
        document.querySelector('.indicator .active').className = '';
        lisb[index].className = 'active';
        h3.innerHTML = `第${index + 1}张图的描述信息`;
        document.querySelector('.slides .active').className = '';
        list[index].className = 'active';
        h3.innerHTML = `第${index + 1}张图的描述信息`;
      });
    </script>
  </body>
</html>