BackTop Vue 3 TypeScript版本
2021-03-31 本文已影响0人
EasyNetCN
BackTop Vue
<template>
<div :class="classes" :style="styles" @click="back">
<slot>
<div :class="innerClasses">
<i class="ivu-icon ivu-icon-ios-arrow-up"></i>
</div>
</slot>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, onBeforeUnmount, onMounted, ref, toRefs } from 'vue'
import { scrollTop } from '../../utils/assist'
import { on, off } from '../../utils/dom'
const prefixCls = 'ivu-back-top'
export default defineComponent({
props: {
height: {
type: Number,
default: 400
},
bottom: {
type: Number,
default: 30
},
right: {
type: Number,
default: 30
},
duration: {
type: Number,
default: 1000
}
},
setup (props, ctx) {
const { height, bottom, right, duration } = toRefs(props)
const backTop = ref(false)
const classes = computed(() => {
return [
`${prefixCls}`,
{
[`${prefixCls}-show`]: backTop.value
}
]
})
const styles = computed(() => {
return {
bottom: `${bottom.value}px`,
right: `${right.value}px`
}
})
const innerClasses = computed(() => {
return `${prefixCls}-inner`
})
const handleScroll = () => {
backTop.value = window.pageYOffset >= height.value
}
const back = () => {
const sTop = document.documentElement.scrollTop || document.body.scrollTop
scrollTop(window, sTop, 0, duration.value)
ctx.emit('on-click')
}
onMounted(() => {
on(window, 'scroll', handleScroll)
on(window, 'resize', handleScroll)
})
onBeforeUnmount(() => {
off(window, 'scroll', handleScroll)
off(window, 'resize', handleScroll)
})
return {
classes,
styles,
innerClasses,
handleScroll,
back
}
}
})
</script>
assist
// scrollTop animation
export const scrollTop = function (el: Element|Window, from = 0, to: number, duration = 500, endCallback?: Function): void {
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = (
window.webkitRequestAnimationFrame ||
function (callback) {
return window.setTimeout(callback, 1000 / 60)
}
)
}
const difference = Math.abs(from - to)
const step = Math.ceil(difference / duration * 50)
function scroll (start: number, end: number, step: number) {
if (start === end) {
endCallback && endCallback()
return
}
let d = (start + step > end) ? end : start + step
if (start > end) {
d = (start - step < end) ? end : start - step
}
if (el === window) {
window.scrollTo(d, d)
} else if (el instanceof Element) {
el.scrollTop = d
}
window.requestAnimationFrame(() => scroll(d, end, step))
}
scroll(from, to, step)
}