置顶按钮是大部分网站都会有的一个功能,尤其是阅读型网站(如知乎,微博)。当网页长度过长,用户在浏览到网页底部的时候想返回顶端,此时置顶按钮可以帮助用户快速到达顶端,而不是通过多次滚动滑轮或者是手动调整滚动条。
Github 上有许多关于置顶按钮的前端类库,但是为了这么小的一个功能,特意去引入一个类库感觉有点没必要,于是准备自己实现一个。
本网站的前端样式很多是参考了知乎的主页,知乎的置顶按钮长得也比较讨喜,于是参考其 CSS 在界面上先实现出来,基本的特点就是固定位置,位于页面底部。
.corner-container {
position: fixed;
bottom: 12px;
right: 12px;
}
由于 Webkit 对于滚动条的位置没有按照标准处理,所以需要自己实现一个函数获得正确的scrollingElement
在参考了以下文章之后,
使用以下语句获得scrollTarget
,以下代码在 chrome,edge 和 IE11 下均能正常工作.
var scrollTarget = document.scrollingElement || document.documentElement;
获得了正确的scrollTarget
之后,通过scrollTarget.scrollTop
可以获取滚动条的偏移位置,
而对其的直接赋值则可以修改滚动条的位置
置顶按钮不是时刻都要显示的,若当前显示的页面已经是网页的顶端,那么点击置顶按钮是没有意义的,所以需要将其隐藏. 对于网页顶端,我倾向于这样定义: 若用户通过转动一圈鼠标滚轮可以到达网页顶部,那么这个位置可被认定为网页顶端.
在代码中,可以通过一个offset
常量来定义:
this.offsetTop = 150;
onScroll = () => {
this.setState({show: this.scrollTarget.scrollTop > this.offsetTop});
};
实现效果:
在拿到scrollingElement
之后,通过scrollTarget.scrollTop = 0
可以直接让页面跳到顶端,
但是这样的变化感觉有点突兀.参照知乎的设计,页面是平稳地滚动到顶端,有类似于动画的效果.
此效果可以用setTimeout
实现,代码如下:
onClick = () => {
this.scrollUp(100);
};
scrollUp = (size = 100) => {
let nextScrollTop = this.scrollTarget.scrollTop - size;
this.scrollTarget.scrollTop = nextScrollTop > 0 ? nextScrollTop : 0;
if (this.scrollTarget.scrollTop > 0) {
setTimeout(this.scrollUp, 1000 / 60);
}
};
实现效果
上面实现的滚动条定长运动基本完成了置顶按钮的功能,但是有一个小缺陷,当需要滚动的距离很长时, 置顶操作需要花费较长的时间. 如果简单地增大步长,则在滚动距离较小的时候失去了动画效果. 经过一番实验,发现其实需要实现的是一个总时间固定的动画效果,代码如下:
onClick = () => {
this.scrollUpBaseTime(100, 60);
};
scrollUpBaseTime = (ms, refreshRate) => {
let stepSize = this.scrollTarget.scrollTop / refreshRate;
this.scrollUp(stepSize, ms / refreshRate);
};
scrollUp = (size, ms) => {
let nextScrollTop = this.scrollTarget.scrollTop - size;
this.scrollTarget.scrollTop = nextScrollTop > 0 ? nextScrollTop : 0;
if (this.scrollTarget.scrollTop > 0) {
setTimeout(this.scrollUp, ms, size, ms);
}
};
实现效果