iT邦幫忙

2024 iThome 鐵人賽

DAY 7
0
自我挑戰組

30 天 vueuse 原始碼閱讀與實作系列 第 7

[Day 7] useParallax - 序章

  • 分享至 

  • xImage
  •  

官方 Demo:https://vueuse.org/core/useParallax/#demo

個人一直很喜歡視差效果,看到官方 Demo 後,似乎是一個幫助我們花少少的力氣就可以實現出視差效果的工具,本來在 useThrottleFn 之後想繼續講 useDebounceFn,但突然覺得有點膩 XD,所以就先跳來 useParallax。

useParallax 核心原始碼

export function useParallax(target, options = {}) {
  const {
    deviceOrientationTiltAdjust = i => i,
    deviceOrientationRollAdjust = i => i,
    mouseTiltAdjust = i => i,
    mouseRollAdjust = i => i,
    window = defaultWindow,
  } = options

  const orientation = reactive(useDeviceOrientation({ window }))
  const screenOrientation = reactive(useScreenOrientation({ window }))
  const {
    elementX: x,
    elementY: y,
    elementWidth: width,
    elementHeight: height,
  } = useMouseInElement(target, { handleOutside: false, window })

  const source = computed(() => {
    if (orientation.isSupported
      && ((orientation.alpha != null && orientation.alpha !== 0) || (orientation.gamma != null && orientation.gamma !== 0))
    ) {
      return 'deviceOrientation'
    }
    return 'mouse'
  })

  const roll = computed(() => {
    if (source.value === 'deviceOrientation') {
      let value: number
      switch (screenOrientation.orientation) {
        case 'landscape-primary':
          value = orientation.gamma! / 90
          break
        case 'landscape-secondary':
          value = -orientation.gamma! / 90
          break
        case 'portrait-primary':
          value = -orientation.beta! / 90
          break
        case 'portrait-secondary':
          value = orientation.beta! / 90
          break
        default:
          value = -orientation.beta! / 90
      }
      return deviceOrientationRollAdjust(value)
    }
    else {
      const value = -(y.value - height.value / 2) / height.value
      return mouseRollAdjust(value)
    }
  })

  const tilt = computed(() => {
    if (source.value === 'deviceOrientation') {
      let value: number
      switch (screenOrientation.orientation) {
        case 'landscape-primary':
          value = orientation.beta! / 90
          break
        case 'landscape-secondary':
          value = -orientation.beta! / 90
          break
        case 'portrait-primary':
          value = orientation.gamma! / 90
          break
        case 'portrait-secondary':
          value = -orientation.gamma! / 90
          break
        default:
          value = orientation.gamma! / 90
      }
      return deviceOrientationTiltAdjust(value)
    }
    else {
      const value = (x.value - width.value / 2) / width.value
      return mouseTiltAdjust(value)
    }
  })

  return { roll, tilt, source }
}

除了根據 mouse event 做視差計算以外,如果裝置有支援 orientation,拿著裝置翻轉的時候,也可以看到視差效果,因為 IOS 裝置需要 requestPermission 才能看到笑果,如果手邊有 Android 裝置的話,可以去官方 Demo 玩玩看~

另外可以看到,useParallax 本身也用到了很多其他 vueuse composition api,以下條列出來:

  • useDeviceOrientation, useScreenOrientation:處理裝置 orientation 相關計算。
  • useMouseInElement:動態計算鼠標位置 & 目標元素寬高等相關資訊。
  • useMouse:useMouseInElement 動態計算鼠標位置的部分是由 useMouse 實作的。
  • useEventListener:在組件 mounted 的時候註冊 event lisnter,在組件 unmounted 的時候自動把 event listener 註銷。useMouse, useMouseInElement 都會用到 useEventListener。

所以先把上面的 API 全部實作完,最後再處理到 useParallax。接下來的順序會是先從 useEventListener 開始,接著是兩個跟滑鼠相關的:useMouse 和 useMouseInElement。再來看兩個跟裝置方向有關的:useDeviceOrientation 和 useScreenOrientation。最後再回到 useParallax。


上一篇
[Day 6] useThrottleFn - unit test & setTimeout 傳入超大負數導致的 bug
下一篇
[Day 8] useEventListener - 參數介紹 & 核心 tryOnScopeDispose
系列文
30 天 vueuse 原始碼閱讀與實作30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言