DOM--网页特效篇

112 阅读4分钟

滚动事件和加载事件

滚动事件

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

事件名:scroll

监听整个页面滚动

代码:

<script>
      // 滚动事件可以添加给整个页面(window,document),也可以添加给某个元素
      // scroll:滚动事件的事件类型为:scroll

      // 监听页面的滚动
      window.addEventListener('scroll',function(){
        console.log('滚动')
      })

      // 监听的元素
      let box= document.querySelector('.box')
      box.addEventListener('scroll',function(){
        console.log('也在滚动')
      })
    </script>

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

加载事件

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

事件名:load

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

● 给 window 添加 load 事件

代码:

<script>
      // 在页面dom结构和资源全部加载完毕之后再执行下面这块代码
      // 可以添加load事件,它在dom结构和外部资源全部加载完毕之后才触发--load
    
      // window的load事件也叫  入口函数
      window.addEventListener('load',function(){
        let btn= document.querySelector('button')
        console.log(btn)

        btn.addEventListener('click',function(){
          console.log(123)
        })
      })
    </script>

<body>
  <div>
    <p>我是p元素</p>
    <button>我是按钮</button>
    <img src="https://img1.baidu.com/it/u=1849701997,2238263017&fm=26&fmt=auto" alt="" />
  </div>
</body>

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

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

事件名:DOMContentLoaded

监听页面DOM加载完毕:

● 给 document 添加 DOMContentLoaded 事件

代码:

<script>
    // DOMContentLoaded:只要dom结构解析完毕就会触发,而不需要外部资源加载完毕
    window.addEventListener('DOMContentLoaded', function () {
      console.log('我触发了DOMContentLoaded')

      let btn = document.querySelector('button')
      console.log(btn)

      btn.addEventListener('click', function () {
        console.log(123)
      })
    })
  </script>

<body>
  <div>
    <p>我是p元素</p>
    <button>我是按钮</button>
    <img src="https://img1.baidu.com/it/u=1849701997,2238263017&fm=26&fmt=auto" alt="" />
  </div>
</body>

元素大小和位置

scroll家族

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

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

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

代码:

<style>
      .box {
        width: 500px;
        height: 200px;
        border: solid;
        /* 默认会产生滚动条 */
        overflow: scroll;
      }
      .son {
        height: 3000px;
        width: 1500px;
        border: 10px solid;
        padding: 20px;
        background: linear-gradient(to bottom, red, blue);
      }
    </style>
  </head>
  <body>
    <div class="box">
      <!-- <div class="son"></div> -->
    </div>
    <script>
      // 添加入口函数
      window.addEventListener('load',function(){
        // 业务处理
        let box= document.querySelector('.box')
        // sceollWidth:可以获取元素的宽度,(内容+padding),不包含滚动条(17)和边框
        console.log(box.scrollWidth)
      })
    </script>

⭐document.documentElement HTML 文档返回对象为HTML元素

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

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

分析:

①:用到页面滚动事件

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

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

代码:

<style>
      body {
        height: 8000px;
        background-image: linear-gradient(red, blue);
      }

      a {
        color: #fff;
      }

      .actGotop {
        position: fixed;
        bottom: 50px;
        right: 50px;
        width: 150px;
        height: 195px;
        display: none;
        z-index: 100;
      }

      .actGotop a,
      .actGotop a:link {
        width: 150px;
        height: 195px;
        display: inline-block;
        background: url(images/gotop.png) no-repeat;
        outline: none;
      }

      .actGotop a:hover {
        width: 150px;
        height: 195px;
        background: url(images/gotop.gif) no-repeat;
        outline: none;
      }
    </style>
  </head>

  <body>
    <!-- 返回顶部小火箭 -->
    <div class="actGotop"><a href="javascript:;" title="Top"></a></div>

    <!-- 需求:
    1.滚动出屏幕的距离超过1000的时候,出现小火箭
    2.单击小火箭能够返回到顶部 -->

    <script>
      window.addEventListener('load', function() {
        // 获取元素
        let actGotop = document.querySelector('.actGotop')
        // 为小火箭添加单击事件
        actGotop.addEventListener('click', function() {
          // 回到顶部
          document.documentElement.scrollTop = 0
        })

        // 监听页面滚动
        window.addEventListener('scroll', function() {
          // 获取页面滚动出屏幕的距离
          let top = document.documentElement.scrollTop
          // 判断卷出的距离是否大于 2000
          if (top >= 2000) {
            // 让小火箭出现
            actGotop.style.display = 'block'
          } else {
            // 让小火箭隐藏
            actGotop.style.display = 'none'
          }
        })
      })
    </script>
  </body>

offset家族

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

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

案例:仿京东固定导航栏

需求:当页面滚动到秒杀模块,导航栏自动滑入,否则滑出

分析:

①:用到页面滚动事件

②:检测页面滚动大于等于 秒杀模块的位置 则滑入,否则滑出

代码:

<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: 600px;
    }
  </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>
    window.addEventListener('load', function () {
      // 获取元素
      let sk = document.querySelector('.sk')
      let header = document.querySelector('.header')
      // 获取当前元素离文档的顶部距离
      let skOffsetTop = sk.offsetTop

      // 添加页面滚动的监听
      window.addEventListener('scroll', function () {
        // 获取当前页面垂直方向滚动出屏幕的距离
        let offset = document.documentElement.scrollTop
        // 判断滚动出的距离和skOffsetTop的大小,如果大于等于则让header出现(样式操作),否则隐藏
        if (offset >= skOffsetTop) {
          header.style.top = 0
        } else {
          header.style.top = '-80px'
        }
      })
    })

  </script>
</body>

案例:电梯导航

需求:点击可以页面调到指定位置

分析:

①:点击当前 小导航,当前添加active,其余移除active

②:得到对应 内容 的 offsetTop值

③:让页面的 scrollTop 走到 对应 内容 的 offsetTop

代码:

<style>
    * {
      margin: 0;
      padding: 0;
    }

    body {
      height: 3000px;
    }

    .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>
    window.addEventListener('load', function () {
      let items = document.querySelectorAll('.item')
      let neirongs = document.querySelectorAll('.neirong')

      // 为左侧导航项绑定事件--伪数组需要遍历
      items.forEach(function (ele, index) {
        ele.addEventListener('click', function () {
          document.querySelector('.item.active').classList.remove('active')
          ele.classList.add('active')

          // 获取与这个导航项对应的内容面板
          let current = neirongs[index]

          // 让页面滚动当前对应的内容面板离顶部的距离
          document.documentElement.scrollTop = current.offsetTop
        })
      });
    })
  </script>
</body>

client家族

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

●获取位置: 获取左边框和上边框宽度 clientLeft和clientTop 注意是只读属性

代码:

<style>
    .box {
      width: 500px;
      height: 500px;
      border: solid red 10px;
      /* 默认会产生滚动条 */
      overflow: scroll;
    }

    .son {
      height: 300px;
      /* width: 1500px; */
      border: 10px solid;
      border-width: 10px 20px 30px 40px;
      /* padding: 20px; */
      background: linear-gradient(to bottom, red, blue);
      /* word-break: break-all; */
    }
  </style>
</head>

<body>
  <div class="box">
    <div class="son">
      66666666666666666666666666666
    </div>
  </div>

  <script>
    window.addEventListener('load',function(){

      let box = document.querySelector('.box')
      let son = document.querySelector('.son')
  
      // scrollWidth:获取内容的高度:包含width + padding ,包含卷出容器的宽高
      // clientWidth:获取内容的可视区域的宽度,不包含滚动条
      console.log(son.scrollWidth, son.clientWidth)
      console.log(son.clientLeft, son.clientTop)
  
      // offsetHeight:获取元素高度:包含 内容 + 边框 + padding
      // clienHeight:内容 + padding的高度
      // clientTop:上边框的高度
      // 求出了底部高度
      console.log(son.offsetHeight - son.clientHeight - son.clientTop)
    })
  </script>
</body>

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

代码:

<style>
      body {
        background-color: red;
      }
    </style>
  </head>
  <body>
    <script>
      window.addEventListener('load',function(){
        // 使用resize监听屏幕窗口大小的变化
        window.addEventListener('resize',function(){
          document.body.style.backgroundColor='red'
          let width = document.documentElement.clientWidth
          if(width>768){
            document.body.style.backgroundColor='green'
          }
          if(width>992){
            document.body.style.backgroundColor='blue'
          }
          if(width>1200){
            document.body.style.backgroundColor='black'
          }
        })
      })
    </script>

综合案例

轮播图案例

分析:

需求①:小图标鼠标经过事件

​ 鼠标经过小图片,当前高亮,其余兄弟变淡 添加类

需求② :大图片跟随变化

​ 对应的大图片跟着显示,如果想要过渡效果,可以使用opacity效果,可以利用CSS淡入 淡出的效果,还是添加类

需求③:右侧按钮播放效果

​ 1、点击右侧按钮,可以自动播放下一张图片

​ 2、需要一个变化量 index 不断自增

​ 3、 然后播放下一张图片

​ 4、如果到了最后一张,必须要还原为第1张图片

​ ●教你一招: 索引号 = 索引号 % 数组长度 (放到播放前面)

需求④:解决一个BUG

​ 点击右侧按钮可以实现播放下一张,但是鼠标经过前面的,播放就会乱序 ​ 解决方案: 让变化量(索引号) 重新赋值为 当前鼠标经过的索引号

需求⑤:左侧按钮播放效果

​ 1、点击左侧按钮,可以自动播放上一张图片

​ 2、需要一个变化量 index 不断自减

​ 3、然后播放上一张图片

​ 4、如果到了第一张,必须要从最后一张播放

​ 5、教你一招: 索引号 = (数组长度 + 索引号) % 数组长度

需求⑥:

​ 因为左侧按钮和右侧按钮里面有大量相同的操作,可以抽取封装一个函数 common

需求⑦:开启定时器

​ 其实定时器自动播放,就相当于点击了右侧按钮,此时只需要, right.click()

需求⑧:

​ 鼠标经过停止定时器 (清除定时器) ​ 鼠标离开开启定时器 (开启定时器)

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

    <!-- 引入js文件 -->
    <script>
      window.addEventListener('load', function () {
    // 1.获取元素
    // 1.1 获取下方的标记
    let indicators = document.querySelectorAll('.indicator li')
    // 1.2  获取所有的图片
    let slides = document.querySelectorAll('.slides li')
    // 1.3 获取图片的描述
    let desc = document.querySelector('.extra > h3')
    // 1.4 获取左右按钮
    let next = document.querySelector('.extra > .next')
    let prev = document.querySelector('.extra > .prev')
  
    // 定义一个全局的索引,用来标记当前图片的位置
    let index = 0
  
    // 2.单击下方的标记,切换图片--为标记绑定事件
    indicators.forEach(function (ind, i) {
      ind.addEventListener('click', function () {
        // 2.1为当前被单击的元素添加样式,清除其它的标记的样式--排他
        // 先清除,再添加
        document.querySelector('.indicator .active').classList.remove('active')
        this.classList.add('active')
  
        // 2.2 让上方出现对应的大图 -- 排他
        // 所谓对应,现阶段就是指  索引对应  ,后期是指id对应
        document.querySelector('.slides li.active').classList.remove('active')
        slides[i].classList.add('active')
  
        // 2.3 显示图片提示
        desc.innerHTML = `第${i + 1}张图的描述信息`
  
        // 2.4 为了避免单击之后,索引值 没有变化,再点击下一张的时候,出现跳跃,需要将索引值重新为当前单击的元素的索引
        index = i
      })
    })
  
    // 3.下一张
    next.addEventListener('click', function () {
      // 3.1 索引 + 1
      index++
  
      // 判断当前索引是否越界,如果越界,重新设置为0--循环轮播
      if (index > indicators.length - 1) {
        index = 0
      }
      // 3.2 切换下方标记的样式
      document.querySelector('.indicator li.active').classList.remove('active')
      indicators[index].classList.add('active')
  
      // 3.3 让上方出现对应的大图 -- 排他
      // 所谓对应,现阶段就是指  索引对应  ,后期是指id对应
      document.querySelector('.slides li.active').classList.remove('active')
      slides[index].classList.add('active')
  
      // 3.4 显示图片提示
      desc.innerHTML = `第${index + 1}张图的描述信息`
    })
  
    // 4.上一张
    prev.addEventListener('click', function () {
      // 4.1 索引 + 1
      index--
  
      // 判断当前索引是否越界,如果越界,重新设置为0--循环轮播
      if (index < 0) {
        index = indicators.length - 1
      }
      // 4.2 切换下方标记的样式
      document.querySelector('.indicator li.active').classList.remove('active')
      indicators[index].classList.add('active')
  
      // 4.3 让上方出现对应的大图 -- 排他
      // 所谓对应,现阶段就是指  索引对应  ,后期是指id对应
      document.querySelector('.slides li.active').classList.remove('active')
      slides[index].classList.add('active')
  
      // 4.4 显示图片提示
      desc.innerHTML = `第${index + 1}张图的描述信息`
    })
  })
  
    </script>
  </body>