概述
在一些页面比较长的时候,可能会用到回到顶部功能,一般都是右下角一个图标我们点击可以返回到顶部,这个功能还是蛮常见的在一些网页中,这里实现一个跟element-ui组件库功能一样的backTop组件。这个功能看起来还是蛮简单的,我们可以自由发挥。
最终效果
- 不带滚动父元素
- 带滚动父元素
实现原理
实现这个功能其实就是给滚动元素添加滚动事件,当超出某个滚动距离的时候显示,反之隐藏,中间我们可以额外加一些过渡动画和节流函数来提升用户体验。
具体实现
App.vue
<template>
<div id="app" class="container" :style="{ height: 2000 + 'px' }">
<div class="test-date-picker">
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<p>this is test scroll event</p>
<!-- 不带滚动父元素的 -->
<back-top
:visibility-height="200"
@backUpClick="handleBackUpClick"
>
</back-top>
<!-- 带滚动父元素的 -->
<!-- <back-top
target=".test-date-picker"
:visibility-height="200"
@backUpClick="handleBackUpClick"
>
</back-top> -->
</div>
</div>
</template>
<script>
import BackTop from "./components/BackTop/index.js";
export default {
name: "App",
components: {
BackTop,
},
methods: {
//点击回到顶部按钮触发事件
handleBackUpClick(e) {
console.log(e);
},
},
};
</script>
<style lang="less">
#app {
.test-date-picker {
width: 400px;
margin: 20px auto;
height: 300px;
background-color: #e8f3fe;
overflow: auto;
}
}
</style>
./components/BackUp/BackTop.vue
<template>
<transition name="back-up-fade">
<div
class="back-top"
:style="{
bottom: bottom + 'px',
right: right + 'px',
}"
@click.stop="handleBackTopClick($event)"
v-if="show"
>
<div class="back-text-contaner">
<!-- 提供了插槽显示插槽内容 -->
<slot v-if="$slots.default"></slot>
<!-- 没提供,使用默认的 -->
<div class="default-text" v-else>UP</div>
</div>
</div>
</transition>
</template>
<script>
// 导入节流函数
import { throttle } from "./utils";
export default {
props: {
// 触发滚动的容器
target: {
type: String,
default: "",
},
// 滚动高度达到此参数值才出现
visibilityHeight: {
type: Number,
default: 200,
},
// 控制其显示位置, 距离页面右边距
right: {
type: Number,
default: 40,
},
// 控制其显示位置, 距离页面底部距离
bottom: {
type: Number,
default: 40,
},
},
data() {
return {
// 滚动容器
container: null,
// 是否显示
show: false,
// 定时器标识
timer: null,
// 包裹元素节点
el: "",
};
},
mounted() {
//节流处理,避免频繁触发事件
this.throttleHandleContanierScroll = throttle(
this.handleContanierScroll,
200,
false
);
this.init();
},
methods: {
init() {
// 默认滚动元素为document
this.container = document;
this.el = document.documentElement;
// 外部传入滚动包裹元素时候
if (this.target) {
const el = document.querySelector(this.target);
el ? (this.container = el && (this.el = el)) : null;
}
console.log(this.container);
this.container.addEventListener(
"scroll",
this.throttleHandleContanierScroll,
false
);
},
// 回到顶部点击
handleBackTopClick(e) {
// 给回到顶部一定过度事件
this.timer = setInterval(() => {
this.scrollToTop();
}, 16);
// 通知用户
this.$emit("backUpClick", e);
},
// 滚动事件
handleContanierScroll() {
// 滚动超出给定高度则显示,否则隐藏
if (this.el.scrollTop > this.visibilityHeight) {
this.show = true;
} else {
this.show = false;
}
},
// 滚动到顶部
scrollToTop() {
if (this.el.scrollTop > 0) {
this.el.scrollTop -= 50;
} else {
clearInterval(this.timer);
}
},
},
beforeDestroy() {
// 销毁定时器
clearInterval(this.timer);
this.timer = null;
},
};
</script>
<style lang="less">
.back-top {
position: fixed;
background-color: #fff;
width: 40px;
height: 40px;
border-radius: 50%;
color: #409eff;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
box-shadow: 0 0 6px rgb(0 0 0 / 12%);
cursor: pointer;
z-index: 5;
}
.back-up-position {
position: relative;
}
// 过度动画
.back-up-fade-enter-active {
transition: opacity 0.3s linear;
}
.back-up-fade-enter {
opacity: 0;
}
.back-up-leave-to {
opacity: 0;
}
</style>
./components/BackUp/utils.js
/**
* @Description 节流函数
* @param { Function } fn 需要做节流的函数
* @param { Function } intervalTime 间隔实践
* @param { Function } immediate 是否立即执行
* @return { Number } intervalTime
**/
export function throttle(fn, intervalTime = 200, immediate = true) {
let oldTime = Date.now();
return function (...arg) {
if (immediate) {
fn.bind(this)(...arg);
immediate = false;
}
let nowTime = Date.now();
if (nowTime - oldTime >= intervalTime) {
fn.bind(this)(...arg);
oldTime = nowTime;
}
};
}
./components/BackUp/index.js
//按需导出组件
import BackTop from "./BackTop.vue";
export default BackTop;
总结
这个组件还是比较简单的,我们可以根据自己需要自行扩展,上面提到的节流函数不懂的可以查下,防抖和节流函数在性能优化上面还是挺常用的。