原生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)
})