• 锚点 定位 导航 滑动


    <template>
      <div>
        <!-- 内容区域 -->
        <div class="content">
          <div>
            content-0
          </div>
          <div>
            content-1
          </div>
          <div>
            content-2
          </div>
          <div>
            content-3
          </div>
          <div>
            content-4
          </div>
        </div>
        <!-- 导航区域 -->
        <ul class="navs">
          <li :class="{active: active===0}" @click="scrollTo(0)">
            content-0
          </li>
          <li :class="{active: active===1}" @click="scrollTo(1)">
            content-1
          </li>
          <li :class="{active: active===2}" @click="scrollTo(2)">
            content-2
          </li>
          <li :class="{active: active===3}" @click="scrollTo(3)">
            content-3
          </li>
          <li :class="{active: active===4}" @click="scrollTo(4)">
            content-4
          </li>
        </ul>
      </div>
    </template>
    
    <script>
    export default {
      props: {},
      data() {
        return {
          active: 0 // 当前激活的导航索引
        }
      },
      mounted() {
        // 监听滚动事件
        window.addEventListener('scroll', this.onScroll, false)
      },
      destroy() {
        // 必须移除监听器,不然当该vue组件被销毁了,监听器还在就会出错
        window.removeEventListener('scroll', this.onScroll)
      },
      methods: {
        // 滚动监听器
        onScroll() {
          // 获取所有锚点元素
          const navContents = document.querySelectorAll('.content div')
          // 所有锚点元素的 offsetTop
          const offsetTopArr = []
          navContents.forEach(item => {
            offsetTopArr.push(item.offsetTop)
          })
          // 获取当前文档流的 scrollTop
          const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
          // 定义当前点亮的导航下标
          let navIndex = 0
          for (let n = 0; n < offsetTopArr.length; n++) {
            // 如果 scrollTop 大于等于第n个元素的 offsetTop 则说明 n-1 的内容已经完全不可见
            // 那么此时导航索引就应该是n了
            if (scrollTop >= offsetTopArr[n]) {
              navIndex = n
            }
          }
          this.active = navIndex
        },
        // 跳转到指定索引的元素
        scrollTo(index) {
          // 获取目标的 offsetTop
          // css选择器是从 1 开始计数,我们是从 0 开始,所以要 +1
          const targetOffsetTop = document.querySelector(`.content div:nth-child(${index + 1})`).offsetTop
          // 获取当前 offsetTop
          let scrollTop = document.documentElement.scrollTop || document.body.scrollTop
          // 定义一次跳 50 个像素,数字越大跳得越快,但是会有掉帧得感觉,步子迈大了会扯到蛋
          const STEP = 50
          // 判断是往下滑还是往上滑
          if (scrollTop > targetOffsetTop) {
            // 往上滑
            smoothUp()
          } else {
            // 往下滑
            smoothDown()
          }
          // 定义往下滑函数
          function smoothDown() {
            // 如果当前 scrollTop 小于 targetOffsetTop 说明视口还没滑到指定位置
            if (scrollTop < targetOffsetTop) {
              // 如果和目标相差距离大于等于 STEP 就跳 STEP
              // 否则直接跳到目标点,目标是为了防止跳过了。
              if (targetOffsetTop - scrollTop >= STEP) {
                scrollTop += STEP
              } else {
                scrollTop = targetOffsetTop
              }
              document.body.scrollTop = scrollTop
              document.documentElement.scrollTop = scrollTop
              // 关于 requestAnimationFrame 可以自己查一下,在这种场景下,相比 setInterval 性价比更高
              requestAnimationFrame(smoothDown)
            }
          }
          // 定义往上滑函数
          function smoothUp() {
            if (scrollTop > targetOffsetTop) {
              if (scrollTop - targetOffsetTop >= STEP) {
                scrollTop -= STEP
              } else {
                scrollTop = targetOffsetTop
              }
              document.body.scrollTop = scrollTop
              document.documentElement.scrollTop = scrollTop
              requestAnimationFrame(smoothUp)
            }
          }
        }
      }
    }
    </script>
    
    <style scoped>
      /* 内容区的样式 */
      .content {
        background-color: white;
        width: 500px;
      }
      .content div {
        width: 100%;
        height: 600px;
        font-size: 36px;
        padding: 20px;
        background-color: #7ec384;
      }
      .content div:nth-child(2n) {
        background-color: #847ec3;
      }
      /* 导航栏的样式 */
      .navs {
        position: fixed;
        top: 80px;
        left: 700px;
        background-color: #efefef;
      }
      .navs li {
        padding: 0 20px;
        line-height: 1.6;
        font-size: 24px;
      }
      /* 当导航被点亮后改变颜色 */
      .navs .active{
        color: #847ec3;
        background-color: #e2e2e2;
      }
    </style>
    
    11人点赞
    web
    
    
    作者:JethroHuang
    链接:https://www.jianshu.com/p/2ad8c8b5bf75
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    随机色块
    JQ命令汇总
    JQ选择器
    cookie
    tab切换
    Ajax跨域
    RocksDB介绍:一个比LevelDB更彪悍的引擎
    谷歌的诀窍:如何取消验证码
    Ruby on Rails创始人DHH谈如何进行混合移动APP开发
    SequoiaDB 架构指南
  • 原文地址:https://www.cnblogs.com/jinsuo/p/13212305.html
Copyright © 2020-2023  润新知