|
@@ -0,0 +1,115 @@
|
|
|
+<template>
|
|
|
+ <div
|
|
|
+ v-show="isShowBackTopBtn"
|
|
|
+ class="back-top"
|
|
|
+ @click="onClickBackTop"
|
|
|
+ >
|
|
|
+ <slot>
|
|
|
+ <div class="back-top__default">
|
|
|
+ 回到顶部
|
|
|
+ </div>
|
|
|
+ </slot>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+const { debounce } = require('@/config/utils.js')
|
|
|
+const TWEEN = require('@tweenjs/tween.js')
|
|
|
+
|
|
|
+export default ({
|
|
|
+ props: {
|
|
|
+ targetId: {
|
|
|
+ type: String,
|
|
|
+ required: true,
|
|
|
+ },
|
|
|
+ triggerDistance: {
|
|
|
+ type: Number,
|
|
|
+ default: 200,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ target: null,
|
|
|
+ isShowBackTopBtn: false,
|
|
|
+ isBackingTop: false,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ onClickBackTop() {
|
|
|
+ if (this.isBackingTop) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.isBackingTop = true
|
|
|
+
|
|
|
+ const tweenTarget = {
|
|
|
+ scrollTop: this.target.scrollTop
|
|
|
+ }
|
|
|
+ new TWEEN.Tween(tweenTarget)
|
|
|
+ .to({ scrollTop: 0 }, 800)
|
|
|
+ .easing(TWEEN.Easing.Quartic.Out)
|
|
|
+ .onUpdate(() => {
|
|
|
+ this.target.scrollTop = tweenTarget.scrollTop
|
|
|
+ })
|
|
|
+ .onComplete(() => {
|
|
|
+ this.isBackingTop = false
|
|
|
+ })
|
|
|
+ .start()
|
|
|
+
|
|
|
+ const animate = (time) => {
|
|
|
+ if (this.isBackingTop) {
|
|
|
+ requestAnimationFrame(animate)
|
|
|
+ TWEEN.update(time)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ requestAnimationFrame(animate)
|
|
|
+
|
|
|
+ // 不想引入tween.js的话,可以用这段简单的匀速滚动代码
|
|
|
+ // const startTime = Date.now()
|
|
|
+ // const totalScroll = this.target.scrollTop
|
|
|
+ // const fn = () => {
|
|
|
+ // if (this.target.scrollTop === 0) {
|
|
|
+ // this.isBackingTop = false
|
|
|
+ // return
|
|
|
+ // }
|
|
|
+
|
|
|
+ // const nowTime = Date.now()
|
|
|
+ // const assumeScrollTop = totalScroll - (nowTime - startTime) * totalScroll / 500
|
|
|
+ // this.target.scrollTop = assumeScrollTop > 0 ? assumeScrollTop : 0
|
|
|
+ // requestAnimationFrame(fn)
|
|
|
+ // }
|
|
|
+ // requestAnimationFrame(fn)
|
|
|
+ },
|
|
|
+ onTargetScroll: debounce(function(e) {
|
|
|
+ if (this.isBackingTop) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (e.target.scrollTop >= this.triggerDistance) {
|
|
|
+ this.isShowBackTopBtn = true
|
|
|
+ } else {
|
|
|
+ this.isShowBackTopBtn = false
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.target = document.getElementById(this.targetId)
|
|
|
+ if (this.target) {
|
|
|
+ this.target.addEventListener('scroll', this.onTargetScroll, {
|
|
|
+ passive: true,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ unmounted() {
|
|
|
+ if (this.target) {
|
|
|
+ this.target.removeEventListener('scroll', this.onTargetScroll, {
|
|
|
+ passive: true,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="less">
|
|
|
+.back-top__default {
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+</style>
|