mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-12-04 04:08:34 +08:00
refactor(components): [backtop] (#10151)
* refactor(components): [backtop] * Extract logic code from component itself. * Reorganize code for better readability. * chore: remove handleScrollThrottled from being returned
This commit is contained in:
parent
79982b8610
commit
84a867f847
@ -6,3 +6,4 @@ export const ElBacktop = withInstall(Backtop)
|
||||
export default ElBacktop
|
||||
|
||||
export * from './src/backtop'
|
||||
export type { BacktopInstance } from './src/instance'
|
||||
|
@ -1,5 +1,4 @@
|
||||
import type { ExtractPropTypes } from 'vue'
|
||||
import type Backtop from './backtop.vue'
|
||||
|
||||
export const backtopProps = {
|
||||
visibilityHeight: {
|
||||
@ -25,5 +24,3 @@ export const backtopEmits = {
|
||||
click: (evt: MouseEvent) => evt instanceof MouseEvent,
|
||||
}
|
||||
export type BacktopEmits = typeof backtopEmits
|
||||
|
||||
export type BacktopInstance = InstanceType<typeof Backtop>
|
||||
|
@ -14,15 +14,15 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref, shallowRef } from 'vue'
|
||||
import { useEventListener, useThrottleFn } from '@vueuse/core'
|
||||
import { computed } from 'vue'
|
||||
import { ElIcon } from '@element-plus/components/icon'
|
||||
import { easeInOutCubic, throwError } from '@element-plus/utils'
|
||||
import { CaretTop } from '@element-plus/icons-vue'
|
||||
import { useNamespace } from '@element-plus/hooks'
|
||||
import { backtopEmits, backtopProps } from './backtop'
|
||||
import { useBackTop } from './use-backtop'
|
||||
|
||||
const COMPONENT_NAME = 'ElBacktop'
|
||||
|
||||
defineOptions({
|
||||
name: COMPONENT_NAME,
|
||||
})
|
||||
@ -31,54 +31,11 @@ const props = defineProps(backtopProps)
|
||||
const emit = defineEmits(backtopEmits)
|
||||
|
||||
const ns = useNamespace('backtop')
|
||||
const el = shallowRef<HTMLElement>()
|
||||
const container = shallowRef<Document | HTMLElement>()
|
||||
const visible = ref(false)
|
||||
|
||||
const { handleClick, visible } = useBackTop(props, emit, COMPONENT_NAME)
|
||||
|
||||
const backTopStyle = computed(() => ({
|
||||
right: `${props.right}px`,
|
||||
bottom: `${props.bottom}px`,
|
||||
}))
|
||||
|
||||
const scrollToTop = () => {
|
||||
// TODO: use https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo, with behavior: 'smooth'
|
||||
|
||||
if (!el.value) return
|
||||
const beginTime = Date.now()
|
||||
const beginValue = el.value.scrollTop
|
||||
const frameFunc = () => {
|
||||
if (!el.value) return
|
||||
const progress = (Date.now() - beginTime) / 500
|
||||
if (progress < 1) {
|
||||
el.value.scrollTop = beginValue * (1 - easeInOutCubic(progress))
|
||||
requestAnimationFrame(frameFunc)
|
||||
} else {
|
||||
el.value.scrollTop = 0
|
||||
}
|
||||
}
|
||||
requestAnimationFrame(frameFunc)
|
||||
}
|
||||
const handleScroll = () => {
|
||||
if (el.value) visible.value = el.value.scrollTop >= props.visibilityHeight
|
||||
}
|
||||
const handleClick = (event: MouseEvent) => {
|
||||
scrollToTop()
|
||||
emit('click', event)
|
||||
}
|
||||
|
||||
const handleScrollThrottled = useThrottleFn(handleScroll, 300, true)
|
||||
|
||||
useEventListener(container, 'scroll', handleScrollThrottled)
|
||||
onMounted(() => {
|
||||
container.value = document
|
||||
el.value = document.documentElement
|
||||
|
||||
if (props.target) {
|
||||
el.value = document.querySelector<HTMLElement>(props.target) ?? undefined
|
||||
if (!el.value) {
|
||||
throwError(COMPONENT_NAME, `target is not existed: ${props.target}`)
|
||||
}
|
||||
container.value = el.value
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
3
packages/components/backtop/src/instance.ts
Normal file
3
packages/components/backtop/src/instance.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import type Backtop from './backtop.vue'
|
||||
|
||||
export type BacktopInstance = InstanceType<typeof Backtop>
|
64
packages/components/backtop/src/use-backtop.ts
Normal file
64
packages/components/backtop/src/use-backtop.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import { onMounted, ref, shallowRef } from 'vue'
|
||||
import { useEventListener, useThrottleFn } from '@vueuse/core'
|
||||
import { easeInOutCubic, throwError } from '@element-plus/utils'
|
||||
|
||||
import type { SetupContext } from 'vue'
|
||||
import type { BacktopEmits, BacktopProps } from './backtop'
|
||||
|
||||
export const useBackTop = (
|
||||
props: BacktopProps,
|
||||
emit: SetupContext<BacktopEmits>['emit'],
|
||||
componentName: string
|
||||
) => {
|
||||
const el = shallowRef<HTMLElement>()
|
||||
const container = shallowRef<Document | HTMLElement>()
|
||||
const visible = ref(false)
|
||||
|
||||
const scrollToTop = () => {
|
||||
// TODO: use https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo, with behavior: 'smooth'
|
||||
|
||||
if (!el.value) return
|
||||
const beginTime = Date.now()
|
||||
const beginValue = el.value.scrollTop
|
||||
const frameFunc = () => {
|
||||
if (!el.value) return
|
||||
const progress = (Date.now() - beginTime) / 500
|
||||
if (progress < 1) {
|
||||
el.value.scrollTop = beginValue * (1 - easeInOutCubic(progress))
|
||||
requestAnimationFrame(frameFunc)
|
||||
} else {
|
||||
el.value.scrollTop = 0
|
||||
}
|
||||
}
|
||||
requestAnimationFrame(frameFunc)
|
||||
}
|
||||
const handleScroll = () => {
|
||||
if (el.value) visible.value = el.value.scrollTop >= props.visibilityHeight
|
||||
}
|
||||
|
||||
const handleClick = (event: MouseEvent) => {
|
||||
scrollToTop()
|
||||
emit('click', event)
|
||||
}
|
||||
|
||||
const handleScrollThrottled = useThrottleFn(handleScroll, 300, true)
|
||||
|
||||
useEventListener(container, 'scroll', handleScrollThrottled)
|
||||
onMounted(() => {
|
||||
container.value = document
|
||||
el.value = document.documentElement
|
||||
|
||||
if (props.target) {
|
||||
el.value = document.querySelector<HTMLElement>(props.target) ?? undefined
|
||||
if (!el.value) {
|
||||
throwError(componentName, `target does not exist: ${props.target}`)
|
||||
}
|
||||
container.value = el.value
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
visible,
|
||||
handleClick,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user