原生js实现平滑滚动
今天上班遇到一个问题,点击某个按钮,将某个div里面含有id的某个元素滚动到视野中央,大概距离视口顶部100px位置。思索良久,没搞出来,今晚回来好生研究,思路如下。
首先了解下关于元素以及浏览器窗口各种尺寸含义
一张图搞清楚 html 定位:ClientHeight,scrollWidth
本教程只需要用到一下几个尺寸
名称 | 含义 |
---|---|
offsetTop | 当前元素距离文档顶部的偏移距离 |
scrollTop | 文档在视口中滚动的距离 |
clientHeight | 视口的高度 |
再列出一张草图
[外链图片转存失败(img-Gxdy4aOl-1563378643916)(C:\Users\Administrator\Desktop\无标题.png)]
从图中分析我们可以得知:
元素临界点(元素上边界贴在视口上边界):offsetTop = scrollTop
元素临界点(元素上边界贴在视口下边界):offsetTop = scrollTop + clientHeight
由此可见只要 offsetTop - scrollTop > 0 && offsetTop - scrollTop < clientHeight ,就可以保证元素在视口区域内。
// html
<button id="btn">点击出现</button>
<div id="d1">
<div id="d2">
<p id="d3">前端开发精髓</p>
</div>
</div>
// js
let d1 = document.getElementById('d1')
let d2 = document.getElementById('d2')
let d3 = document.getElementById('d3')
let clientHeight = d1.clientHeight
console.log('clientHeight', clientHeight)
console.log('offsetTop', d3.offsetTop)
d1.onscroll = () => {
let clientHeight = d1.clientHeight
let scrollTop = d1.scrollTop
let offsetTop = d3.offsetTop
let into = offsetTop - scrollTop > 0 && offsetTop - scrollTop < clientHeight
if (into) {
console.log('我在可视区域内')
}
}
我们要实现的功能是点击按钮将带id的元素滚动到视野中央距离顶部100px
// 这种可以平滑滚动到视野中央,但是不是距离顶部100px
let btn = document.getElementById('btn')
btn.onclick = () => {
// 方法一: 使用 scrollIntoView()
d3.scrollIntoView({
behavior: 'smooth',
block: 'center'
})
}
// 原生JS, 说实话实现
let btn = document.getElementById('btn')
btn.onclick = () => {
let scroll = 100
let offsetTop = d3.offsetTop
let clientHeight = d1.clientHeight
// 总长度
let scrollLength = offsetTop - 100
// 总花费200ms
let time = 200
let step = scrollLength / time
let interval = setInterval(() => {
if (d1.scrollTop >= scrollLength) {
clearInterval(interval)
}
d1.scrollTop += step
}, 1);
}
// 很显然,滑动过程很慢,总话费市场并不只有200ms,我知道总时长,但是我无法用定时器实现200ms滑动了scrollLength,所以我又采用了jquery的animate函数
// 使用了jquery
$('#btn').click(function(){
let scroll = 100
let offsetTop = $('#d3').offsetTop
let clientHeight = $('#d1').clientHeight
// 总长度
let scrollLength = offsetTop - 100
// 总花费200ms
let time = 200
let step = scrollLength / time
$('#d1').animate({scrollTop: scrollLength },200)
})