12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 |
- import { onBeforeUnmount, onMounted, ref } from 'vue'
- import { isClient } from '@vueuse/core'
- import { throttleAndDebounce } from '../utils'
- const threshold = 960
- const cubic = (value: number): number => value ** 3
- const easeInOutCubic = (value: number): number =>
- value < 0.5 ? cubic(value * 2) / 2 : 1 - cubic((1 - value) * 2) / 2
- export const useBackTop = (offset = 200) => {
- const shouldShow = ref(false)
- const throttleResize = throttleAndDebounce(onResize, 300)
- const throttleScroll = throttleAndDebounce(onScroll, 160)
- onMounted(() => {
- if (!isClient) return
- onResize()
- onScroll()
- window.addEventListener('resize', throttleResize)
- })
- onBeforeUnmount(() => {
- if (!isClient) return
- window.removeEventListener('resize', throttleResize)
- window.removeEventListener('scroll', throttleScroll)
- })
- const scrollToTop = () => {
- const beginTime = Date.now()
- const beginValue = document.documentElement.scrollTop
- const rAF = window.requestAnimationFrame
- const frameFunc = () => {
- const progress = (Date.now() - beginTime) / 500
- if (progress < 1) {
- document.documentElement.scrollTop =
- beginValue * (1 - easeInOutCubic(progress))
- rAF(frameFunc)
- } else {
- document.documentElement.scrollTop = 0
- }
- }
- rAF(frameFunc)
- }
- function onResize() {
- if (!isClient) return
- const { clientWidth } = document.body
- if (clientWidth < threshold) {
- window.addEventListener('scroll', throttleScroll)
- } else {
- window.removeEventListener('scroll', throttleScroll)
- }
- }
- function onScroll() {
- if (!isClient) return
- shouldShow.value = document.documentElement.scrollTop > offset
- }
- return {
- shouldShow,
- scrollToTop,
- }
- }
|