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)
}
上一篇 下一篇

猜你喜欢

热点阅读