element-plus/docs/.vitepress/vitepress/composables/back-top.ts
2022-03-25 15:35:56 +08:00

68 lines
1.7 KiB
TypeScript

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,
}
}