vue一個fixedHeader指令吧!

很多網站都會使用到頁面往下滑動時header吸附至頂端的功能這次就寫個vue自定義指令來完成這個功能!

知識點

  1. 動態加入style sheet
  2. 獲取滾動條上放位置兼容寫法
  3. offsetHeight
#js
export default {
  install (Vue) {
    // 優化
    function debounce (cb, delay) {
      let timer = null
      return function () {
        clearTimeout(timer)
        timer = setTimeout(cb, delay)
      }
    }
    // 自動添加css檔案
    function loadCssCode (code) {
      // 防止我方公司preRender造成的重複添加問題
      if (window.__PRERENDER_PROCESSING) return
      const style = document.createElement('style')
      style.type = 'text/css'
      style.rel = 'stylesheet'
      try {
        style.appendChild(document.createTextNode(code))
      } catch (ex) {
        style.styleSheet.cssText = code
      }
      const head = document.getElementsByTagName('head')[0]
      head.appendChild(style)
    }
    // 核心邏輯(頁面Y大於麼幫元素自身高度兩倍距離的時候加上fixed樣式與動效反之則移除)
    function fixHandler (el, fixPosY) {
      // 兼容寫法獲取滾輪上方位置數值
      const screenTop = Math.max(
        window.pageYOffset,
        document.documentElement.scrollTop,
        document.body.scrollTop
      )
      const headerHeight = el.offsetHeight
      if (el.classList.contains('fixe-top-header--active') && screenTop >= fixPosY + headerHeight * 2) return
      if (screenTop > fixPosY + headerHeight * 2) {
        el.classList.add('fixe-top-header--active')
        el.classList.add('fixe-top-header--fadeIn')
        el.classList.remove('fixe-top-header--fadeOut')
      } else {
        el.classList.remove('fixe-top-header--active')
        el.classList.remove('fixe-top-header--fadeIn')
        el.classList.add('fixe-top-header--fadeOut')
      }
    }

    Vue.directive('fixe-top', {
      inserted (el, binding) {
        // 參數css名稱(必傳),動效名稱,
        const { cssName, animationNameIn, animationNameOut, duration, zIndex } = binding.value
        // 初始化樣式與動效
        loadCssCode(`
        .${cssName}--active{
          position:fixed;
          left:0;
          top:0;
          right:0;
          z-index:${zIndex || 999}
        }
        .${cssName}--fadeIn{
          animation: ${animationNameIn || ' fixe-fade-in'}  ${(duration || 1000) / 1000}s;
          }
        .${cssName}--fadeOut{
          animation: ${animationNameOut || ' fixe-fade-Out'}  ${(duration || 1000) / 1000}s;
          }
          @keyframes fixe-fade-in {
            from {
              opacity: 0;
            }
          
            to {
              opacity: 1;
            }
         }
          @keyframes fixe-fade-Out {
            from {
              opacity: 0;
            }
          
            to {
              opacity: 1;
            }
         }
       `)
        // 目標元素
        const fixPosY = el.offsetTop
        window.addEventListener(
          'scroll',
          debounce(() => fixHandler(el, fixPosY), 10)
        )
      }
    })
  }
}
#註冊
import ScrollFixTop from '@/plugins/scrollFixTop'
Vue.use(ScrollFixTop)
#使用
      v-fixe-top="{
        cssName:'fixe-top-header' //定位的目標className,
        animationNameIn:'', //fix時的動畫
        animationNameOut:'', //fix拔掉時的動畫
        duration:1000, 
        zIndex:30 //目標fix後的層級
      }"

參考:

https://shubo.io/element-size-scrolling/