1. 程式人生 > 實用技巧 >錨點 定位 導航 滑動

錨點 定位 導航 滑動

<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 來源:簡書 著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。