BackTop はページのトップにスクロールする機能で、多くのウェブサイトで使用される基本的な機能です。実現方法は多く、Github には smooth-scroll のような優れたサードパーティライブラリもありますが、優雅に実現することもまた一つの技術です。
イベントのバインディングとアンバインディング#
ページのトップにスクロールするボタンは一般的にページの隅に位置し、必要なときにのみ表示されます。したがって、まずはページのスクロールイベントを監視し、一定の距離までスクロールした後に BackTop ボタンを表示する必要があります。
ページのスクロールを監視する最も簡単な実装方法は、addEventListener
を使用して scroll イベントをリッスンし、ページがアンロードされるときにリスナーを解除することです。コードは以下の通りです:
window.addEventListener('scroll', handleScroll, false)
window.removeEventListener('scroll', handleScroll, false)
しかし、最も優雅な実装方法と呼ばれるからには、さまざまなブラウザに対応するために、バインディングとアンバインディングのイベントを共通のメソッドに抽出し、互換性を最適化する必要があります。コードは以下の通りです:
/**
* @description イベントをバインドする on(element, event, handler)
*/
export const on = (function() {
if (document.addEventListener) {
return function(element, event, handler) {
if (element && event && handler) {
element.addEventListener(event, handler, false)
}
}
} else {
return function(element, event, handler) {
if (element && event && handler) {
element.attachEvent('on' + event, handler)
}
}
}
})()
/**
* @description イベントをアンバインドする off(element, event, handler)
*/
export const off = (function() {
if (document.removeEventListener) {
return function(element, event, handler) {
if (element && event) {
element.removeEventListener(event, handler, false)
}
}
} else {
return function(element, event, handler) {
if (element && event) {
element.detachEvent('on' + event, handler)
}
}
}
})()
呼び出し方:
on(window, 'scroll', handleScroll)
off(window, 'scroll', handleScroll)
function handleScroll() {
console.log(window.pageYOffset)
}
トップに戻るアニメーション#
window.requestAnimationFrame()
メソッドは、ブラウザが次回の再描画の前に指定された関数を呼び出してアニメーションを更新するようリクエストします。このメソッドはコールバック関数を引数として使用し、このコールバック関数はブラウザが再描画する前に呼び出されます。コールバックの回数は通常、1秒あたり60回です。互換性の問題のため、異なるブラウザではプレフィックスを付ける必要があり、ブラウザがサポートしていない場合は setTimeout を使用してシミュレートします。
requestAnimationFrame の目的は、さまざまなウェブページアニメーション効果(DOM アニメーション、Canvas アニメーション、SVG アニメーション、WebGL アニメーション)が統一されたリフレッシュメカニズムを持つことを可能にし、システムリソースを節約し、システムパフォーマンスを向上させ、視覚効果を改善することです。
requestAnimationFrame
を使用してページのトップにスクロールするアニメーションを実現するための核心は、フレームごとに小さな距離をスクロールしてスムーズなスクロール効果を実現することです。コードは以下の通りです:
// scrollTop アニメーション
export function scrollTop(el, from = 0, to, duration = 500, endCallback) {
if (!window.requestAnimationFrame) {
window.requestAnimationFrame =
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
return window.setTimeout(callback, 1000 / 60)
}
}
const difference = Math.abs(from - to)
const step = Math.ceil((difference / duration) * 50)
function scroll(start, end, step) {
if (start === end) {
endCallback && endCallback()
return
}
let d = start + step > end ? end : start + step
if (start > end) {
d = start - step < end ? end : start - step
}
if (el === window) {
window.scrollTo(d, d)
} else {
el.scrollTop = d
}
window.requestAnimationFrame(() => scroll(d, end, step))
}
scroll(from, to, step)
}
呼び出し方:
function backTop() {
const sTop = document.documentElement.scrollTop || document.body.scrollTop
scrollTop(window, sTop, 0, 2000)
}
拡張:この API は cancelAnimationFrame
メソッドも提供しており、再描画をキャンセルするために使用されます。引数は requestAnimationFrame
が返すタスク ID を表す整数値です。使用方法は以下の通りです:
const requestID = window.requestAnimationFrame(() => scroll(d, end, step))
window.cancelAnimationFrame(requestID)
ブラウザの互換性を考慮しない場合、Chrome や Firefox ブラウザでは、window.scrollTo
は第二の引数形式をサポートしており、引数 options
は三つの属性を含むオブジェクトです:
- top は y-coord に相当し、縦軸の座標を表します。
- left は x-coord に相当し、横軸の座標を表します。
- behavior は String 型で、スクロールの動作を示し、smooth(スムーズスクロール)、instant(瞬時スクロール)をサポートし、デフォルト値は auto で、instant と同等の効果があります。
window.scrollTo({
top: 0,
behavior: 'smooth'
})
この方法はシンプルで効率的ですが、Edge、IE、Safari ではサポートされていません。