プラグインやフレームワークの干渉なしに、UIに生のJavaScriptコードのみを使用したいページをコーディングしています。
そして今、私はjQueryなしでページをスムーズにスクロールする方法を見つけるのに苦労しています。
プラグインやフレームワークの干渉なしに、UIに生のJavaScriptコードのみを使用したいページをコーディングしています。
そして今、私はjQueryなしでページをスムーズにスクロールする方法を見つけるのに苦労しています。
回答:
このスムーズなスクロールデモ、または次のようなアルゴリズムを試してください。
self.pageYOffsetelement.offsetTopwindow.scrollToこの質問に対する他の一般的な回答も参照してください。
Andrew Johnsonの元のコード:
function currentYPosition() {
// Firefox, Chrome, Opera, Safari
if (self.pageYOffset) return self.pageYOffset;
// Internet Explorer 6 - standards mode
if (document.documentElement && document.documentElement.scrollTop)
return document.documentElement.scrollTop;
// Internet Explorer 6, 7 and 8
if (document.body.scrollTop) return document.body.scrollTop;
return 0;
}
function elmYPosition(eID) {
var elm = document.getElementById(eID);
var y = elm.offsetTop;
var node = elm;
while (node.offsetParent && node.offsetParent != document.body) {
node = node.offsetParent;
y += node.offsetTop;
} return y;
}
function smoothScroll(eID) {
var startY = currentYPosition();
var stopY = elmYPosition(eID);
var distance = stopY > startY ? stopY - startY : startY - stopY;
if (distance < 100) {
scrollTo(0, stopY); return;
}
var speed = Math.round(distance / 100);
if (speed >= 20) speed = 20;
var step = Math.round(distance / 25);
var leapY = stopY > startY ? startY + step : startY - step;
var timer = 0;
if (stopY > startY) {
for ( var i=startY; i<stopY; i+=step ) {
setTimeout("window.scrollTo(0, "+leapY+")", timer * speed);
leapY += step; if (leapY > stopY) leapY = stopY; timer++;
} return;
}
for ( var i=startY; i>stopY; i-=step ) {
setTimeout("window.scrollTo(0, "+leapY+")", timer * speed);
leapY -= step; if (leapY < stopY) leapY = stopY; timer++;
}
}
関連リンク:
JavaScriptでのネイティブブラウザのスムーズなスクロールは次のようになります。
// scroll to specific values,
// same as window.scroll() method.
// for scrolling a particular distance, use window.scrollBy().
window.scroll({
top: 2500,
left: 0,
behavior: 'smooth'
});
// scroll certain amounts from current position
window.scrollBy({
top: 100, // negative value acceptable
left: 0,
behavior: 'smooth'
});
// scroll to a certain element
document.querySelector('.hello').scrollIntoView({
behavior: 'smooth'
});
speedオプションが必要です。現在のスクロール速度は、フローするには遅すぎます。
編集:この回答は2013年に書かれました。requestAnimationFrameに関する以下のCristianTraìnaのコメントを確認してください
やった。以下のコードは、フレームワークに依存していません。
制限:アクティブなアンカーはURLに書き込まれません。
コードのバージョン:1.0 | Github:https://github.com/Yappli/smooth-scroll
(function() // Code in a function to create an isolate scope
{
var speed = 500;
var moving_frequency = 15; // Affects performance !
var links = document.getElementsByTagName('a');
var href;
for(var i=0; i<links.length; i++)
{
href = (links[i].attributes.href === undefined) ? null : links[i].attributes.href.nodeValue.toString();
if(href !== null && href.length > 1 && href.substr(0, 1) == '#')
{
links[i].onclick = function()
{
var element;
var href = this.attributes.href.nodeValue.toString();
if(element = document.getElementById(href.substr(1)))
{
var hop_count = speed/moving_frequency
var getScrollTopDocumentAtBegin = getScrollTopDocument();
var gap = (getScrollTopElement(element) - getScrollTopDocumentAtBegin) / hop_count;
for(var i = 1; i <= hop_count; i++)
{
(function()
{
var hop_top_position = gap*i;
setTimeout(function(){ window.scrollTo(0, hop_top_position + getScrollTopDocumentAtBegin); }, moving_frequency*i);
})();
}
}
return false;
};
}
}
var getScrollTopElement = function (e)
{
var top = 0;
while (e.offsetParent != undefined && e.offsetParent != null)
{
top += e.offsetTop + (e.clientTop != null ? e.clientTop : 0);
e = e.offsetParent;
}
return top;
};
var getScrollTopDocument = function()
{
return document.documentElement.scrollTop + document.body.scrollTop;
};
})();
var _updateURL = function ( anchor, url ) { if ( (url === true || url === 'true') && history.pushState ) { history.pushState( {pos:anchor.id}, '', anchor ); } };(ChrisFernandiのSmoothScroll jsを介して)のようなものを使用して、アンカーURLを履歴スタックにプッシュするだけでURLにアンカーを書き込むことができると思います。単に「JQueryを使用する」のではなく、これを行っている人々を見るのはうれしいです!:targetちなみに、セレクターも優れたソリューションです。
要素をスクロールするには、scrollTop時間の経過とともにその値を変更する必要があります。特定の時点で、新しいscrollTop値を計算します。スムーズにアニメーション化するには、smooth-stepアルゴリズムを使用して補間します。
scrollTop次のように計算します。
var point = smooth_step(start_time, end_time, now);
var scrollTop = Math.round(start_top + (distance * point));
どこ:
start_time アニメーションが開始された時間です。end_timeアニメーションが終了するとき(start_time + duration)です;start_topはscrollTop最初の値です。そしてdistanceは、目的の終了値と開始値の差です(target - start_top)。堅牢なソリューションは、アニメーションが中断されたときなどを検出する必要があります。詳細については、jQueryを使用しないスムーズスクロールに関する私の投稿を読んでください。
コード:
/**
Smoothly scroll element to the given target (element.scrollTop)
for the given duration
Returns a promise that's fulfilled when done, or rejected if
interrupted
*/
var smooth_scroll_to = function(element, target, duration) {
target = Math.round(target);
duration = Math.round(duration);
if (duration < 0) {
return Promise.reject("bad duration");
}
if (duration === 0) {
element.scrollTop = target;
return Promise.resolve();
}
var start_time = Date.now();
var end_time = start_time + duration;
var start_top = element.scrollTop;
var distance = target - start_top;
// based on http://en.wikipedia.org/wiki/Smoothstep
var smooth_step = function(start, end, point) {
if(point <= start) { return 0; }
if(point >= end) { return 1; }
var x = (point - start) / (end - start); // interpolation
return x*x*(3 - 2*x);
}
return new Promise(function(resolve, reject) {
// This is to keep track of where the element's scrollTop is
// supposed to be, based on what we're doing
var previous_top = element.scrollTop;
// This is like a think function from a game loop
var scroll_frame = function() {
if(element.scrollTop != previous_top) {
reject("interrupted");
return;
}
// set the scrollTop for this frame
var now = Date.now();
var point = smooth_step(start_time, end_time, now);
var frameTop = Math.round(start_top + (distance * point));
element.scrollTop = frameTop;
// check if we're done!
if(now >= end_time) {
resolve();
return;
}
// If we were supposed to scroll but didn't, then we
// probably hit the limit, so consider it done; not
// interrupted.
if(element.scrollTop === previous_top
&& element.scrollTop !== frameTop) {
resolve();
return;
}
previous_top = element.scrollTop;
// schedule next frame for execution
setTimeout(scroll_frame, 0);
}
// boostrap the animation process
setTimeout(scroll_frame, 0);
});
}
pageYOffsetとを使用する必要がありscrollTo()ました。elementscrollTop
ここでjQueryなしの例を作成しました:http://codepen.io/sorinnn/pen/ovzdq
/**
by Nemes Ioan Sorin - not an jQuery big fan
therefore this script is for those who love the old clean coding style
@id = the id of the element who need to bring into view
Note : this demo scrolls about 12.700 pixels from Link1 to Link3
*/
(function()
{
window.setTimeout = window.setTimeout; //
})();
var smoothScr = {
iterr : 30, // set timeout miliseconds ..decreased with 1ms for each iteration
tm : null, //timeout local variable
stopShow: function()
{
clearTimeout(this.tm); // stopp the timeout
this.iterr = 30; // reset milisec iterator to original value
},
getRealTop : function (el) // helper function instead of jQuery
{
var elm = el;
var realTop = 0;
do
{
realTop += elm.offsetTop;
elm = elm.offsetParent;
}
while(elm);
return realTop;
},
getPageScroll : function() // helper function instead of jQuery
{
var pgYoff = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
return pgYoff;
},
anim : function (id) // the main func
{
this.stopShow(); // for click on another button or link
var eOff, pOff, tOff, scrVal, pos, dir, step;
eOff = document.getElementById(id).offsetTop; // element offsetTop
tOff = this.getRealTop(document.getElementById(id).parentNode); // terminus point
pOff = this.getPageScroll(); // page offsetTop
if (pOff === null || isNaN(pOff) || pOff === 'undefined') pOff = 0;
scrVal = eOff - pOff; // actual scroll value;
if (scrVal > tOff)
{
pos = (eOff - tOff - pOff);
dir = 1;
}
if (scrVal < tOff)
{
pos = (pOff + tOff) - eOff;
dir = -1;
}
if(scrVal !== tOff)
{
step = ~~((pos / 4) +1) * dir;
if(this.iterr > 1) this.iterr -= 1;
else this.itter = 0; // decrease the timeout timer value but not below 0
window.scrollBy(0, step);
this.tm = window.setTimeout(function()
{
smoothScr.anim(id);
}, this.iterr);
}
if(scrVal === tOff)
{
this.stopShow(); // reset function values
return;
}
}
}
window.setTimeout = window.setTimeout;
最新のブラウザは、CSSの「scroll-behavior:smooth」プロパティをサポートしています。したがって、このためにJavascriptはまったく必要ありません。これをbody要素に追加し、通常のアンカーとリンクを使用するだけです。 スクロール動作MDNドキュメント
私は最近、jQueryがオプションではなかった状況でこの問題を解決しようと試みたので、後世のためにここに解決策を記録しています。
var scroll = (function() {
var elementPosition = function(a) {
return function() {
return a.getBoundingClientRect().top;
};
};
var scrolling = function( elementID ) {
var el = document.getElementById( elementID ),
elPos = elementPosition( el ),
duration = 400,
increment = Math.round( Math.abs( elPos() )/40 ),
time = Math.round( duration/increment ),
prev = 0,
E;
function scroller() {
E = elPos();
if (E === prev) {
return;
} else {
prev = E;
}
increment = (E > -20 && E < 20) ? ((E > - 5 && E < 5) ? 1 : 5) : increment;
if (E > 1 || E < -1) {
if (E < 0) {
window.scrollBy( 0,-increment );
} else {
window.scrollBy( 0,increment );
}
setTimeout(scroller, time);
} else {
el.scrollTo( 0,0 );
}
}
scroller();
};
return {
To: scrolling
}
})();
/* usage */
scroll.To('elementID');
このscroll()関数は、Revealing Module Patternを使用してscrolling()、を介してターゲット要素のIDを関数に渡しscroll.To('id')ます。これにより、によって使用される値が設定されます。scroller()関数でます。
壊す
でscrolling():
el :ターゲットDOMオブジェクトelPos :を介して関数を返します elememtPosition()呼び出されるたびに、ページの上部を基準にしたターゲット要素の位置を指定。duration :ミリ秒単位の遷移時間。increment :ターゲット要素の開始位置を40ステップに分割します。time :各ステップのタイミングを設定します。prev:ターゲット要素の前の位置scroller()。E:ターゲット要素の位置をscroller()。に保持します。実際の作業は、ターゲット要素がページの上部に来るか、ページがスクロールできなくなるまで、scroller()(を介してsetTimeout())自身を呼び出し続ける関数によって行われます。
scroller()呼び出されるたびに、ターゲット要素(変数に保持されているE)の現在の位置がチェックされ、それが> 1OR< -1であるかどうか、ページがまだスクロール可能であるかどうかは、ウィンドウが正または負の値であるかincrementどうかに応じてピクセル単位で上下にシフトしますE。Eが> 1ORでも< -1、E===prevでもない場合、関数は停止します。追加しましたDOMElement.scrollTo()ターゲット要素がウィンドウの上部で強打されていることを確認するために、完了時にメソッド(ピクセルの何分の1かで外れていることに気付かないでください!)。
if2行目のステートメントscroller()はE、前の位置(prev)と照合して、ページがスクロールしているかどうかを確認します(ターゲットがページの下部に向かっていて、ページがそれ以上スクロールできない場合)。
その下の3値条件は、ゼロに近づくにつれてincrement値を減らしEます。これにより、ページが一方の方向にオーバーシュートし、次に跳ね返ってもう一方の方向にオーバーシュートし、次に跳ね返ってもう一方の方向にオーバーシュートし、ピンポンスタイルで無限のかなたになります。
ページの高さが約4000pxを超える場合は、3項式の最初の条件(ここでは+/- 20)および/またはincrement値を設定する除数(ここでは40)の値を増やすことができます。
約遊ぶdurationセット除数、incrementとの三元状態での値scroller()ページに合うように調整する機能を、あなたを可能にしなければなりません。
NBLubuntuではFirefoxとChromeの最新バージョンで、Windows8ではFirefox、Chrome、IEでテスト済み。
スクロール動作プロパティを使用することもできます。たとえば、CSSに以下の行を追加します
html{
scroll-behavior:smooth;
}
これにより、ネイティブのスムーズなスクロール機能が実現します。 スクロール動作についてもっと読む
私はこのようなものを作りました。IE8で動作するかどうかはわかりません。IE9、Mozilla、Chrome、Edgeでテスト済み。
function scroll(toElement, speed) {
var windowObject = window;
var windowPos = windowObject.pageYOffset;
var pointer = toElement.getAttribute('href').slice(1);
var elem = document.getElementById(pointer);
var elemOffset = elem.offsetTop;
var counter = setInterval(function() {
windowPos;
if (windowPos > elemOffset) { // from bottom to top
windowObject.scrollTo(0, windowPos);
windowPos -= speed;
if (windowPos <= elemOffset) { // scrolling until elemOffset is higher than scrollbar position, cancel interval and set scrollbar to element position
clearInterval(counter);
windowObject.scrollTo(0, elemOffset);
}
} else { // from top to bottom
windowObject.scrollTo(0, windowPos);
windowPos += speed;
if (windowPos >= elemOffset) { // scroll until scrollbar is lower than element, cancel interval and set scrollbar to element position
clearInterval(counter);
windowObject.scrollTo(0, elemOffset);
}
}
}, 1);
}
//call example
var navPointer = document.getElementsByClassName('nav__anchor');
for (i = 0; i < navPointer.length; i++) {
navPointer[i].addEventListener('click', function(e) {
scroll(this, 18);
e.preventDefault();
});
}
説明
pointer-属性が「href」の場合は要素とchceckを取得し、「#」の場合は削除します。elem-「#」のないポインタ変数elemOffset-ページ上部からの「スクロール先」要素のオフセット使用できます
document.querySelector('your-element').scrollIntoView({behavior: 'smooth'});
ページの上部を上にスクロールする場合は、空の要素を上部に配置して、その要素までスムーズにスクロールできます。
window.scrollToとsetTimeoutでforループを使用して、プレーンなJavascriptでスムーズにスクロールできます。私のscrollToSmoothly関数で要素にスクロールするには:scrollToSmoothly(elem.offsetTop)(elemDOM要素であると仮定します)。これを使用して、ドキュメント内の任意のy位置にスムーズにスクロールできます。
function scrollToSmoothly(pos, time){
/*Time is only applicable for scrolling upwards*/
/*Code written by hev1*/
/*pos is the y-position to scroll to (in pixels)*/
if(isNaN(pos)){
throw "Position must be a number";
}
if(pos<0){
throw "Position can not be negative";
}
var currentPos = window.scrollY||window.screenTop;
if(currentPos<pos){
var t = 10;
for(let i = currentPos; i <= pos; i+=10){
t+=10;
setTimeout(function(){
window.scrollTo(0, i);
}, t/2);
}
} else {
time = time || 2;
var i = currentPos;
var x;
x = setInterval(function(){
window.scrollTo(0, i);
i -= 10;
if(i<=pos){
clearInterval(x);
}
}, time);
}
}
デモ:
<script>
var set = 0;
function animatescroll(x, y) {
if (set == 0) {
var val72 = 0;
var val73 = 0;
var setin = 0;
set = 1;
var interval = setInterval(function() {
if (setin == 0) {
val72++;
val73 += x / 1000;
if (val72 == 1000) {
val73 = 0;
interval = clearInterval(interval);
}
document.getElementById(y).scrollTop = val73;
}
}, 1);
}
}
</script>
x = scrollTop
y =スクロールに使用されるdivのID
注:
本体をスクロールさせるには、本体にIDを指定します。
これが私の解決策です。ほとんどのブラウザで動作します
document.getElementById("scrollHere").scrollIntoView({behavior: "smooth"});
document.getElementById("end").scrollIntoView({behavior: "smooth"});
body {margin: 0px; display: block; height: 100%; background-image: linear-gradient(red, yellow);}
.start {display: block; margin: 100px 10px 1000px 0px;}
.end {display: block; margin: 0px 0px 100px 0px;}
<div class="start">Start</div>
<div class="end" id="end">End</div>
これが私のために働いたコードです。
`$('a[href*="#"]')
.not('[href="#"]')
.not('[href="#0"]')
.click(function(event) {
if (
location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '')
&&
location.hostname == this.hostname
) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) + ']');
if (target.length) {
event.preventDefault();
$('html, body').animate({
scrollTop: target.offset().top
}, 1000, function() {
var $target = $(target);
$target.focus();
if ($target.is(":focus")) {
return false;
} else {
$target.attr('tabindex','-1');
$target.focus();
};
});
}
}
});
`