js的三大家族(offset/scroll/client)/经典电梯导航案例

222 阅读1分钟

offset家族

作用

获取元素 ‘自身’ 宽高与位置

  • 元素.offsetWidth / 元素.offsetHeight
    • width+padding+border
  • 元素.offsetLeft / 元素.offsetTop
    • 自身 到 定位父元素 左/上 内边框距离 示例如下:
<!DOCTYPE html>
<html>

<head lang="en">
  <meta charset="UTF-8" />
  <title>标题</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    div {
      width: 150px;
      height: 150px;
      background-color: pink;
      overflow: auto;
      padding: 10px;
      border: 10px solid red;
      margin: 100px;
    }
  </style>
</head>

<body>
  <div class="box">
    我有很多很多的内容哦 我有很多很多的内容哦 我有很多很多的内容哦
    我有很多很多的内容哦 我有很多很多的内容哦 我有很多很多的内容哦
    我有很多很多的内容哦 我有很多很多的内容哦 我有很多很多的内容哦
    我有很多很多的内容哦 我有很多很多的内容哦 我有很多很多的内容哦
    我有很多很多的内容哦 我有很多很多的内容哦 我有很多很多的内容哦
  </div>

  <script>
  

    let box = document.querySelector('.box')
    //三大家族是dom语法,不是css样式。
    //错误写法: 元素.style.offsetWidth
    //正确写法: 元素.offsetWidth
    // 1. offset家族
    console.log(box.offsetWidth, box.offsetHeight)// 190 190
    console.log(box.offsetLeft, box.offsetTop)// 100 100

    //2. scroll家族
    console.log( box.scrollWidth , box.scrollHeight )//153 419
    console.log( box.scrollLeft , box.scrollTop )//0 0 默认没有滚动

    //3. client家族
    console.log( box.clientWidth , box.clientHeight ) // 153 170
    console.log( box.clientLeft , box.clientTop ) // 10 10
    

  </script>
</body>

</html>

scroll家族

作用

获取元素 ‘内容’ 宽高与位置

  • 元素.scrollWidth / 元素.scrollHeight
    • 内容宽高
  • 元素.scrollLeft / 元素.scrollTop
    • 内容位置 : 滚动条滚动的距离 示例代码如下:
<!DOCTYPE html>
<html>

<head lang="en">
    <meta charset="UTF-8">
    <title>标题</title>
    <style>
        body {
            width: 3000px;
            height: 3000px;
        }
    </style>
</head>

<body>

    <script>
        /* 获取网页滚动距离 
            1.给页面注册滚动事件 :  window.onscroll
            2.获取页面滚动距离 : document.documentElement.scrollTop
        */

        //1.给页面注册滚动条事件  onscroll
        window.onscroll = function () {
            //2.获取页面滚动的距离  html标签的scrollTop
            console.log(document.documentElement.scrollLeft, document.documentElement.scrollTop)
        }

    </script>
</body>

</html>

应用

案例示例如下:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        * {
            margin: 0;
            padding: 0
        }

        img {
            vertical-align: top;
        }

        .main {
            margin: 0 auto;
            width: 1000px;
            margin-top: 10px;
        }

        .fixed {
            position: fixed;
            top: 0;
            left: 0;
        }
    </style>
</head>

<body>

<div class="top" id="topPart">
    <img id="pic" src="images/top.png" alt=""/>
</div>

<div class="nav" id="navBar">
    <img src="images/nav.png" alt=""/>
</div>

<div class="main" id="mainPart">
    <img src="images/main.png" alt=""/>
</div>

<script>
    /* 思路
    1. 注册页面滚动事件 : 判断 页面滚动距离 与  top盒子高度 关系
        (1)如果 页面距离 >= 盒子高度 : 设置导航盒子nav为固定定位 (添加类名fixed)
        (2)否则 : 设置导航盒子nav为标准流(移除类名fixed)
    */

    //1.获取元素
    let topPart = document.querySelector('.top')
    let navBar = document.querySelector('.nav')
    let mainPart = document.querySelector('.main')

    //2.给页面注册滚动事件
    window.onscroll = function(){
        //3.判断页面滚动距离 与  topPart高度关系
        if( document.documentElement.scrollTop >= topPart.offsetHeight ){
            navBar.classList.add('fixed')
            /* 细节注意点: 固定定位会脱标,导致下面标准流瞬间闪上去(顿闪)
            解决方案: 设置下面盒子的marginTop, 撑开脱标的高度
            */
           mainPart.style.marginTop = 10 + navBar.offsetHeight + 'px'
        }else{
            navBar.classList.remove('fixed')
            //回到标准流, marginTop也要恢复
            mainPart.style.marginTop = 10  + 'px'
        }
    }
</script>
</body>
</html>

client家族

作用

获取元素 ‘可视区域’ 宽高与位置

  • 元素.clientWidth / 元素clientHeight
    • 视口大小
  • 元素.clientLeft / 元素.clientTop
    • 左边框和上边框宽度

应用

  • 响应式(横竖屏适配) 示例如下:
<!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>
</head>

<body>
    <script>
        /* client家族应用 : 响应式布局
        
        1.响应式布局 : 一个页面适配多个不同设备 
        2.响应式布局设备 :
            大PC        :  >= 1200px
            小pc,大平板  :  992px - 1200px
            平板        : 768px - 992px
            手机        :  < 768px
        3.响应式布局原理
            3.1 监听设备视口大小 : 媒体查询、clientWidth
            3.2 根据视口大小加载不同的样式
        */

        //1.给页面注册视口大小变化  onresize
        window.onresize = function(){
            //2.获取视口大小 (页面可视区域大小)
            let w =  document.documentElement.clientWidth
            let h =  document.documentElement.clientHeight
            console.log(w,h)
            if( w >= 1200 ){
                document.body.style.backgroundColor = 'red'
            }else if( w >= 992 ){//隐藏条件  w < 1200
                document.body.style.backgroundColor = 'orange'
            }else if( w >= 768 ){//隐藏条件  w < 992
                document.body.style.backgroundColor = 'yellow'
            }else{//隐藏条件  w < 768
                document.body.style.backgroundColor = 'green'
            }
            
            /* 横竖屏适配 */
            if( w > h ){
                alert('横屏')
            }else{
                alert('竖屏')
            }
        }
       


    </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;
    }

    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>
    /* 思路分析
    1.点击左侧每一个列表
      1.1 排他思想修改样式 :  类名排他active
      1.2 页面滚动到下标一致盒子位置 : 
        页面滚动 document.documentElement.scrollTop
        盒子位置 neirongList[i].offsetTop
    */

    //1.获取元素
    let itemList = document.querySelectorAll('.aside>.item')//左侧列表
    let neirongList = document.querySelectorAll('.content>.neirong')//左侧列表

    //2.点击每一个列表
    for (let i = 0; i < itemList.length; i++) {
      itemList[i].onclick = function () {
        //3.事件处理
        //3.1 排他思想修改样式 :  类名排他active
        //(1)干掉兄弟
        document.querySelector('.item.active').classList.remove('active')
        //(2)复活自己
        this.classList.add('active')
        //3.2 页面滚动到下标一致盒子的位置
        document.documentElement.scrollTop = neirongList[i].offsetTop
      }
    }

    /* 3. 页面滚动事件 : 当前显示的盒子对应下标 的 左侧列表高亮
        左侧列表高亮 : 排他修改类型
        显示的盒子对应下标 :  第一个比 页面滚动距离 大的盒子
    */
    window.onscroll = function () {
      //遍历盒子的scrollTop,找第一个比 页面滚动距离 大的盒子
      for (let i = 0; i < neirongList.length; i++) {
        // console.log(`页面滚动距离${document.documentElement.scrollTop}`)
        // console.log(`第${i}个盒子位置${neirongList[i].offsetTop}` )
        if (neirongList[i].offsetTop  + 100 > document.documentElement.scrollTop) {
          //排他修改左边下标的类名
          document.querySelector('.item.active').classList.remove('active')
          //复活i下标列表
          itemList[i].classList.add('active')
          //一旦找到第一个 位置 比 页面滚动距离大的盒子,就必须要break结束循环
          break
        }
      }
    }
  </script>
</body>

</html>