back-top
- 属性
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
target | 触发滚动的对象 | String | |
visibility-height | 滚动高度达到此参数值才出现 | Number | 300 |
right | 控制其显示位置, 距离页面右边距 | Number | 40 |
bottom | 控制其显示位置, 距离页面底部距离 | Number | 40 |
rollback | 是否保持上一次离开页面时的滚动高度 | Boolean | false |
transition-name | 自动生成 CSS 过渡类名 | String | “fade” |
- 示例
<back-top target=".container" :visibility-height="200" :right="50" :bottom="50" rollback />
- 完整代码
<template>
<transition :name="transitionName">
<div
v-if="visible"
@click.stop="handleClick"
:style="{
right: styleRight,
bottom: styleBottom,
}"
class="back-to-ceiling"
>
<svg
t="1647588320093"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="4746"
width="32"
height="32"
>
<path
d="M684.544 574.08c0 43.221333-24.277333 69.632-70.058667 69.632H409.514667c-45.44 0-69.717333-26.410667-69.717334-69.632v-56.234667h-119.893333c-27.733333 0-49.237333-16.469333-49.237333-41.856 0-15.445333 7.168-26.752 22.570666-40.490666l277.077334-244.608c14.336-12.373333 26.666667-20.224 41.685333-20.224s27.306667 7.893333 42.026667 20.224l276.736 244.266666c14.72 13.056 22.570667 25.386667 22.570666 40.832 0 25.386667-21.546667 41.813333-48.853333 41.813334h-119.936v56.32z m-287.36-1.706667c0 11.648 8.234667 19.541333 19.498667 19.541334h190.634666a18.901333 18.901333 0 0 0 19.498667-19.541334V477.013333c0-7.893333 3.072-10.965333 10.922667-10.965333h136.661333c2.389333 0 3.413333-1.024 3.413333-2.773333 0-1.024-0.341333-2.389333-2.048-3.754667L518.826667 236.544c-2.730667-2.432-4.437333-3.413333-6.826667-3.413333-2.048 0-3.754667 0.981333-6.485333 3.413333l-257.28 222.976c-1.365333 1.365333-2.048 2.730667-2.048 3.754667 0 1.706667 1.024 2.773333 3.413333 2.773333H386.56c7.509333 0 10.581333 3.072 10.581333 10.965333v95.36zM625.109333 853.333333c37.930667 0 59.776-21.248 59.776-60.032v-47.701333c0-38.058667-21.845333-60.373333-59.776-60.373333H396.501333c-37.930667 0-60.16 22.656-60.16 60.373333v47.701333c0 38.4 22.229333 60.032 60.16 60.032h228.608z m-219.008-49.066666c-10.965333 0-16.768-5.802667-16.768-16.469334v-36.352c0-10.965333 5.802667-17.493333 16.768-17.493333h209.408c10.624 0 16.768 6.528 16.768 17.493333v36.352c0 10.666667-6.144 16.469333-16.768 16.469334H406.101333z"
p-id="4747"
fill="#ffffff"
></path>
</svg>
</div>
</transition>
</template>
<script>
import throttle from "throttle-debounce/throttle";
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: "Backtop",
props: {
visibilityHeight: {
type: Number,
default: 300,
},
target: [String],
right: {
type: Number,
default: 40,
},
bottom: {
type: Number,
default: 40,
},
rollback: {
type: Boolean,
default: false,
},
transitionName: {
type: String,
default: "fade",
},
},
data() {
return {
el: null,
container: null,
visible: false,
scrollValue: null,
};
},
computed: {
styleBottom() {
return `${this.bottom}px`;
},
styleRight() {
return `${this.right}px`;
},
},
mounted() {
this.init();
this.throttledScrollHandler = throttle(300, this.onScroll);
this.container.addEventListener("scroll", this.throttledScrollHandler);
},
methods: {
init() {
this.container = document;
this.el = document.documentElement;
if (this.target) {
this.el = document.querySelector(this.target);
if (!this.el) {
throw new Error(`target is not existed: ${this.target}`);
}
this.container = this.el;
}
},
onScroll() {
const scrollTop = this.el.scrollTop;
this.visible = scrollTop >= this.visibilityHeight;
this.scrollValue = scrollTop;
},
handleClick(e) {
this.scrollToTop();
this.$emit("click", e);
},
scrollToTop() {
const el = this.el;
const beginTime = Date.now();
const beginValue = el.scrollTop;
const rAF =
window.requestAnimationFrame || ((func) => setTimeout(func, 16));
const frameFunc = () => {
const progress = (Date.now() - beginTime) / 500;
if (progress < 1) {
el.scrollTop = beginValue * (1 - easeInOutCubic(progress));
rAF(frameFunc);
} else {
el.scrollTop = 0;
}
};
rAF(frameFunc);
},
},
activated() {
this.visible = this.el.scrollTop >= this.visibilityHeight;
if (this.rollback) {
this.el.scrollTop = this.scrollValue;
}
},
beforeDestroy() {
this.container.removeEventListener("scroll", this.throttledScrollHandler);
},
};
</script>
<style lang="scss" scoped>
.back-to-ceiling {
position: fixed;
display: inline-block;
height: 35px;
width: 35px;
line-height: 35px;
border-radius: 50%;
text-align: center;
cursor: pointer;
background: #aaa;
opacity: 0.4;
transition: opacity 0.3s;
&:hover {
opacity: 1;
}
.Icon {
fill: #9aaabf;
background: none;
}
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
</style>