Vue 導航欄固定在頂部,錨點內容綁定(雙向),監(jiān)聽滾動事件,平滑滾動

最近給營銷市場部做了個H5頁面,頁面大概要求就是一個單獨的H5頁面,頂部導航欄固定含有三個導航按鈕必須和正文對應內容聯(lián)動。
首先想到需要用到錨點,但是單純的錨點功能會顯得滾動條很突兀一下子就跳到內容區(qū)了,效果很不理想,然后單純的一個H5頁面去引進jQuery庫肯定也是不合理的,所以必須自己去監(jiān)聽滾動條實現(xiàn)功能。

1.首先按照要求固定頭部導航欄
導航欄
<div class="header-main" :style="getColor()">
    <div class="h5-header">
        <div class="header-left"><i class="okicon icon-0121"></i></div>
        <div class="header-right">
            <span :class="{active: active == 0}">OKKONG OS</span>
            <span :class="{active: active == 1}">系統(tǒng)亮點</span>
            <span :class="{active: active == 2}">聯(lián)系客服</span>
        </div>
     </div>
</div>

固定導航欄css
其中有個小細節(jié)就是因為大div里設置了背景圖,導航欄的背景色要求是設置成0.15,這個時候我們背景色應該使用rgba,第四個參數(shù)寫上透明度0.15(小本本記好),這個就可以解決以后背景圖和背景色需要同時存在的情況了

.header-main{
    min-width: 1200px;
    background:rgba(255, 255, 255, 0.15);
    position: fixed;
    top:0;
    left: 0;
    right: 0;
  }

設置選中導航按鈕的樣式

.active{
        color: #FFA624;
        border-bottom: 4px solid #FFA624;
        font-weight: 800;
      }

初始data里active值為0,默認選中第一個導航按鈕

data(){
    return {
      active: 0, // 當前激活的導航索引
      scrollTop:'',//滾動距離
    }
}

接下來我們就需要監(jiān)聽滾動事件handleScroll()

handleScroll () {
      const scrollTop = document.documentElement.scrollTop || document.body.scrollTop//獲取滾動距離
      this.scrollTop = scrollTop//data里return了一個全局的scrollTop
      console.log(scrollTop)
      //這邊距離我是通過打印scrollTop大致自己粗略的計算了下,用來判斷滾輪滾動相應的距離改變導航欄對應菜單樣式
      if (scrollTop > 1115) {
        this.active = 1
      }
      if(scrollTop > 1850){
        this.active = 2
      }
      if(scrollTop < 1000){
        this.active = 0
      }
    }

頂部導航欄還有個樣式就是需要滾動下去時改變導航欄背景色,這個時候我們就需要給導航欄添加動態(tài)的style樣式

<div class="header-main" :style="getColor()">

樣式方法

getColor(){
      //當滾動距離超過導航欄高度時改變背景色
      if(this.scrollTop > 45){
        return {
          background:"#487DFE"
        }
      }else{
        return false
      }
    }

最重要的一個環(huán)節(jié)就是給導航菜單欄添加點擊滾動事件scrollTo()

給三個導航按鈕增加點擊事件

<div class="header-right">
       <span :class="{active: active == 0}" @click="scrollTo(1)">OKKONG OS</span>
       <span :class="{active: active == 1}" @click="scrollTo(2)">系統(tǒng)亮點</span>
       <span :class="{active: active == 2}" @click="scrollTo(3)">聯(lián)系客服</span>
 </div>

定義scrollTo()方法

具體需要注意的地方和相應的解釋在代碼中已經給出

//跳轉到指定元素
    scrollTo(val){
      // 定義一次跳 50 個像素,數(shù)字越大跳得越快,但是會有掉幀得感覺
      const STEP = 50
      let scrollTop = document.documentElement.scrollTop || document.body.scrollTop//獲取滾動距離
      var targetOffsetTop = ''
      if(val == 1){
        targetOffsetTop = document.querySelector('.h5-os').offsetTop - 60//獲取指定元素視口距離
      }
      if(val == 2){
        targetOffsetTop = document.querySelector('.h5-oslight').offsetTop - 60//獲取指定元素視口距離
      }
      if(val == 3){
        targetOffsetTop = document.querySelector('.contactService').offsetTop - 60//獲取指定元素視口距離
      }
      if (scrollTop < targetOffsetTop) {
        // 往下滑
        smoothDown()
        console.log(targetOffsetTop,'視口距離')
      }else{
        console.log(targetOffsetTop,'targetOffsetTop')
        smoothUp()
      }
      // 定義下滑函數(shù)
      function smoothDown() {
        console.log(scrollTop,'scrollTop')
        // 如果當前 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 的函數(shù)
          // 關于 requestAnimationFrame 可以自己查一下,在這種場景下,相比 setInterval 性價比更高
          requestAnimationFrame(smoothDown)
        }
      }
      // 定義上滑函數(shù)
      function smoothUp() {
        // 如果當前 scrollTop 大于 targetOffsetTop 說明視口已經滑過指定位置需要上滑
        if (scrollTop > targetOffsetTop) {
          // 如果和目標相差距離大于等于 STEP 就跳減去 STEP
          // 否則直接跳到目標點,目標是為了防止跳過了。
          if (scrollTop - targetOffsetTop >= STEP) {
            scrollTop -= STEP
          } else {
            scrollTop = targetOffsetTop
          }
           document.body.scrollTop = scrollTop
           document.documentElement.scrollTop = scrollTop
          // 屏幕在繪制下一幀時會回調傳給 requestAnimationFrame 的函數(shù)
          // 關于 requestAnimationFrame 可以自己查一下,在這種場景下,相比 setInterval 性價比更高
          requestAnimationFrame(smoothUp)
        }
      }
    },

最后在mounted()中監(jiān)聽滾動事件,代碼如下

mounted() {
    // 監(jiān)聽滾動事件
    // document.getElementById("blockmain").addEventListener("scroll", this.handleScroll)
    // window.addEventListener('scroll', this.handleScroll)
    this.$nextTick(function () {
      window.addEventListener('scroll', this.handleScroll)
    })
  },

需要注意的是在組件銷毀時我們需要移除滾動監(jiān)聽器,不然監(jiān)聽器會報錯

destroy() {
    // 必須移除監(jiān)聽器,不然當該vue組件被銷毀了,監(jiān)聽器還在就會出錯
    window.removeEventListener('scroll', this.handleScroll)
  }

以上便是此次滾動事件平滑滾動和錨點雙向功能的實現(xiàn)邏輯

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容