自制回到顶部组件


注意全局回到顶部可能 target 为 window

一. VUE

<template>
    <div>
        <div
          v-if="top"
          @click.stop="topClick"
          :style="{
          'right': styleRight,
          'bottom': moveBottom,
          'position': position,
          'z-index': zIndex
          }"
          class="zoehis_backtop"
          :class="[topLight && lightClass,customClass]">
        <slot name="top">
          <i :class="'zoehis_backtop_icon zoeIconfont z_move_normal'"></i>
        </slot>
        </div>
        <div
          v-if="down"
          @click.stop="bottomClick"
          :style="{
          'right': styleRight,
          'bottom': downBottom,
          'position': position,
          'z-index': zIndex
          }"
          class="zoehis_backtop"
          :class="[bottomLight && lightClass,customClass]">
        <slot name="bottom">
          <i :class="'zoehis_backtop_icon zoeIconfont z_down_normal'"></i>
        </slot>
        </div>
    </div>
</template>

<script>
// 节流函数
import throttle from "../../../src/utils/throttle-debounce.js";

// 缓动函数 https://www.xuanfengge.com/easeing/easeing/#easeInOutCubic
const cubic = value => Math.pow(value, 3);
const easeInOutCubic = value => value < 0.5
  ? cubic(value * 2) / 2
  : 1 - cubic((1 - value) * 2) / 2;

export default {
  name: 'ZoehisBackTop',
  props: {
    visibilityHeight: { // 滚动高度达到此参数值才出现,为0一直存在,没开
      type: Number,
      default: 0
    },
    target: { // 触发滚动的对象
      type: String,
      default: 'html'
    },
    right: { // 控制其显示位置, 距离页面右边距
      type: String,
      default: '79'
    },
    bottom: { // 控制其显示位置,距离页面底部距离
      type: String,
      default: '116'
    },
    isDown: { // 是否显示回到底部
      type: Boolean,
      default: true
    },
    position: { // 控制组件是否根据target定位,fixed/absolute
      type: String,
      default: 'absolute'
    },
    zIndex: { // 自定义层级
      type: String,
      default: '100'
    },
    customClass: { //自定义类名
      type: String,
      default: ''
    },
    lightClass: { // 自定义触顶或触底高亮类名
      type: String,
      default: 'zoehis_backtop_light'
    },
    isRAF: { // 判断是否使用动画效果
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      el: null, // 触发滚动的对象
      top: false, // 回到顶部是否可见
      down: false, // 回到底部是否可见
      topLight: false, // 判断回到顶部高亮
      bottomLight: false, // 判断回到底部高亮
    };
  },
  computed: {
    moveBottom() {
      const re = /^[0-9]+\.?[0-9]*$/;
      if (re.test(this.bottom)) {
        return `${this.bottom}px`
      }
      return this.bottom
    },
    downBottom() {
      const re = /^[0-9]+\.?[0-9]*$/;
      if (re.test(this.bottom)) {
        return `calc(${this.bottom}px - 51px)`
      }
      return `calc(${this.bottom} - 51px)`
    },
    styleRight() {
      const re = /^[0-9]+\.?[0-9]*$/;
      if (re.test(this.right)) {
        return `${this.right}px`
      }
      return this.right
    }
  },
  mounted() {
    this.init();
    this.onScroll();
	// 监听scroll使用节流函数(throttle)
    this.throttledScrollHandler = throttle(50, this.onScroll);
	// 添加scroll事件监听
	this.el.addEventListener('scroll', this.throttledScrollHandler)
  },
  methods: {
    // 初始化判断this.target是否存在
    init() {
      if (this.target) {
        this.el = document.querySelector(this.target);
        if (!this.el) {
          throw new Error(`target 的参数不存在: ${this.target}`);
        }
      }
      // 判断是否显示回到底部
      if (this.isDown === false) {
        this.down = false
      } else {
        this.down = true;
      }
      this.top = true
    },
    // 获取位置后根据位置改变组件颜色
    onScroll() {
	  // 获取元素的内容垂直滚动的像素数。
      const scrollTop = this.el.scrollTop
      this.topLight = parseFloat(scrollTop.toFixed(0)) != 0
      this.bottomLight = parseFloat(scrollTop.toFixed(0)) < this.el.scrollHeight - this.el.clientHeight - 5
	  // 滚动高度达到此参数值  操作按钮才出现
      // this.visible = scrollTop >= this.visibilityHeight;
    },
    // 点击按钮触发的事件
    topClick(e) {
      this.scrollToTop();
      this.$emit('topClick', e);
    },
    bottomClick(e) {
      this.scrollToBottom();
      this.$emit('bottomClick', e);
    },
    // 返回页面顶部的操作
    scrollToTop() {
      const el = this.el;
      // 点击按钮时间戳 UTC毫秒数
      const beginTime = Date.now();
      const beginValue = el.scrollTop;
      const rAF = window.requestAnimationFrame || (func => setTimeout(func, 20));
      const frameFunc = () => {
        // 设置速率 500 毫秒内返回页面顶部
        const progress = (Date.now() - beginTime) / 500;
        if (progress < 1) {
          el.scrollTop = beginValue * (1 - easeInOutCubic(progress));
          rAF(frameFunc);
        } else {
          // 超过 500 毫秒直接返回页面顶部
          el.scrollTop = 0;
        }
      };
      if (this.isRAF) {
        rAF(frameFunc);
      } else {
        el.scrollTop = 0;
      }
    },
    // 返回页面底部的操作
    scrollToBottom() {
      const el = this.el;
      // 点击按钮时间戳 UTC毫秒数
      const beginTime = Date.now();
      const beginValue = el.scrollHeight - el.clientHeight;
      const rAF = window.requestAnimationFrame || (func => setTimeout(func, 16));
      const frameFunc = () => {
        // 设置速率 500 毫秒内返回页面底部
        const progress = (Date.now() - beginTime) / 500;
        if (progress < 1) {
          el.scrollTop = beginValue * (easeInOutCubic(progress)) + el.scrollTop;
          rAF(frameFunc);
        } else {
          // 超过 500 毫秒直接返回页面底部
          el.scrollTop = el.scrollHeight - el.clientHeight;
        }
      };
      if (this.isRAF) {
        rAF(frameFunc);
      } else {
        el.scrollTop = el.scrollHeight - el.clientHeight;
      }
    },
  },
  beforeDestroy() {
    // 删除scroll事件监听
    this.el.removeEventListener('scroll', this.onScroll);
  }
};
</script>

二. index

 import ZoehisBackTop from './src/backTop.vue';
 export default ZoehisBackTop;

三. SCSS

.zoehis_backtop{
  background-color: $MAINBG;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0px 1px 3.92px 0.08px rgba(220, 220, 220, 0.66);
  cursor: pointer;
  z-index: 100;
  .zoehis_backtop_icon {
    color: $BACKTOPICONCOLOR;
    font-size: 26px;
  }
  &:hover {
    background-color: $CLINIMAINHOVER;
  }
}
.zoehis_backtop_light{
  background-color: $CLINIMAIN;
}
posted @ 2022-01-24 17:36  暗鸦08  阅读(59)  评论(0)    收藏  举报