以前大部分时间都是在做b端相关的项目,在实现此类需求时,通常都是直接借助a
标签搞定,现在做c端了,对交互性的要求一下就提升了,此时a
标签就远远不能满足要求了,需要借助js来实现此类需求,特此记录。
a 标签
首先放出html
<body>
<contain class="test1">
<a name="topAnchor"></a>
<div id="top">我是顶部</div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</contain>
<footer>
<button id="backTop1">第一种方式回到顶部</button>
<button id="backTop2">第二种方式回到顶部</button>
<button id="backTop3">第三种方式回到顶部</button>
</footer>
</body>
然后具体操作步骤如下
- 将a标签放到指定元素的附近
- 然后通过点击事件生成
a
标签 - 触发
a
标签事件 - 删除
a
标签
代码如下
const backTop1 = document.getElementById("backTop1")
backTop1.addEventListener("click", function (e) {
let a = document.createElement("a")
a.href = "#topAnchor"
e.target.appendChild(a)
a.onclick = function (e) {
e.stopPropagation()
}
a.click()
e.target.removeChild(a)
})
效果如下图所示
效果很明显,在事件触发之后,页面立马跑到的顶部,在交互性没啥要求的时候,这种做法确实没啥问题,不过要求高了之后就不行了,会显得有些突兀。
scrollTo()
此 api 需要传递 DOM元素相对于window的 left 和 top 的距离,此例子仅展示简单demo,只考虑 top 坐标
当然它还有一个 behavior 参数,将其设置为 smooth 后,将会出现滑动效果
步骤如下:
- 计算目标元素距离顶部的距离
- 通过事件触发
代码如下:
const backTop2 = document.getElementById("backTop2")
const TOP = document.getElementById("top")
const y = TOP.offsetTop
const backTop3 = document.getElementById("backTop3")
backTop3.addEventListener("click", function (e) {
window.scrollTo({ top: y, left: 0, behavior: 'smooth' })
})
效果如下图所示
从效果上来看,相较于a
标签,该api支持动画,使得页面更丝滑
Element.scrollIntoView()
该 api 相较于上一个,节点信息更加的明确,操作方法也更加的简洁,更利于后续的维护
代码如下
const backTop2 = document.getElementById("backTop2")
const TOP = document.getElementById("top")
backTop2.addEventListener("click", function (e) {
TOP.scrollIntoView({ behavior: "smooth" })
})
效果如下图所示
从效果上来看,该api和scrollTo的作用是一致的,但是从代码结构上来说,scrollIntoView会更加的简洁
上面三个的动画效果都有一些兼容问题,本来说昨天处理的,结果昨天加班太晚,给鸽了
废话不多说,开始正题:
通用版的js控制回到页面顶部
const distance=70;// 滚动条每次滚动的距离
function up(){
let start = document.documentElement.scrollTop;
function gotop() {
scrollTo(0, start - distance)
start = start - distance
if (start >0 ){
window.requestAnimationFrame(gotop)
}
}
window.requestAnimationFrame(gotop)
}
本来说用定时器的,后面参考elementUi中的 backTop 组件源码,用了requestAnimationFrame。源码如下:
const cubic = value => Math.pow(value, 3);
const easeInOutCubic = value => value < 0.5
? cubic(value * 2) / 2
: 1 - cubic((1 - value) * 2) / 2;
scrollToTop() {
const el = this.el;// 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);
}
它是用了一个数学曲线来搞的滚动,无论页面内容多高,回到顶部都是差不多的时间,我写的就比较死板,直接写死的70,囧。
有兴趣的话可以去研究,element ui源码传送门
本文完整示例,传送门