自制回到顶部组件
注意全局回到顶部可能 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;
}
本文来自博客园,作者:暗鸦08,转载请注明原文链接:https://www.cnblogs.com/DarkCrow/p/15767679.html

浙公网安备 33010602011771号