플러그인이나 프레임 워크의 간섭없이 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에 대한 아래 Cristian Traì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 ); } };( Chris Fernandi의 Smooth Scroll js를 통해) 와 같은 방식으로 앵커 URL을 히스토리 스택에 푸시하면 됩니다. 사람들이 "JQuery를 사용"하는 것보다 이것을하는 것을 보니 반갑습니다! 기록을 위해 :target선택 자도 깔끔한 솔루션입니다.
요소를 스크롤하려면 scrollTop시간이 지남에 따라 값을 변경해야합니다 . 주어진 시점에 대해 새 scrollTop값을 계산하십시오 . 부드럽게 애니메이션하려면 부드러운 단계 알고리즘을 사용하여 보간 합니다 .
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_topscrollTop시작 부분 의 값입니다. 과distance원하는 종료 값과 시작 값의 차이 (target - start_top)입니다.강력한 솔루션은 애니메이션이 중단되는시기 등을 감지해야합니다. 자세한 내용은 jQuery없는 부드러운 스크롤 에 대한 내 게시물을 읽어보십시오 .
JSFiddle을 참조하십시오 .
코드:
/**
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()에 element대신 scrollTop.
여기에 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()함수는 사용 밝히려 모듈 패턴 의 상기 대상 소자의 ID를 전달 scrolling()통해 함수 scroll.To('id')에 의해 사용되는 값으로 설정하는 scroller()기능.
고장
에서 scrolling():
el : 대상 DOM 객체elPos: elememtPosition()호출 될 때마다 페이지 상단을 기준으로 대상 요소의 위치를 제공 하는 함수를 반환합니다 .duration : 전환 시간 (밀리 초).increment : 대상 요소의 시작 위치를 40 단계로 나눕니다.time : 각 단계의 타이밍을 설정합니다.prev:에서 대상 요소의 이전 위치 scroller().E:에서 대상 요소의 위치를 유지합니다 scroller().실제 작업은 대상 요소가 페이지의 맨 위에 있거나 페이지가 더 이상 스크롤 할 수 없을 때까지 scroller()계속 자신을 호출 하는 함수 (를 통해 setTimeout())에 의해 수행됩니다 .
scroller()호출 될 때마다 대상 요소의 현재 위치 (variable에 유지됨 E)를 확인하고 그것이 > 1OR < -1이고 페이지가 여전히 스크롤 가능한 경우 창을 increment픽셀 단위 로 이동합니다 ( E양수 또는 음수 값에 따라 위 또는 아래로) . 경우 E인도 > 1OR < -1또는 E=== prev기능이 정지한다. DOMElement.scrollTo()대상 요소가 창의 맨 위에 있는지 확인하기 위해 완료시 메서드를 추가했습니다 (픽셀의 일부만 표시되는 것은 아닙니다!).
if2 행 의 명령문 은 이전 위치 ( )를 scroller()확인하여 페이지가 스크롤 중인지 확인합니다 (대상이 페이지 하단을 향하고 페이지가 더 이상 스크롤 할 수없는 경우 ). Eprev
그 아래의 삼항 조건 은 0에 가까워 지면 increment값을 줄 E입니다. 이렇게하면 페이지가 한 방향으로 오버 슈팅 한 다음 다시 바운스되어 다른 쪽을 오버 슈트 한 다음 다시 바운스되어 다른 쪽을 오버 슈트, 핑퐁 스타일, 무한대 및 그 이상으로 중지됩니다.
페이지가 c.4000px 이상인 경우 삼항 표현식의 첫 번째 조건 (여기서는 +/- 20) 및 / 또는 increment값 을 설정하는 제수 (여기서는 40) 의 값을 늘릴 수 있습니다 .
에 대해 재생 duration, 세트 제수 increment의 삼항 조건, 그리고 값이 scroller()맞춤 당신을 허용해야하는 기능은 페이지를 이용할 수 있습니다.
NB Lubuntu의 최신 버전의 Firefox 및 Chrome, Windows8의 Firefox, Chrome 및 IE에서 테스트되었습니다.
Scroll Behavior Property를 사용할 수도 있습니다 . 예를 들어 아래 줄을 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>
다음 부드러운 스크롤을 사용하면 잘 작동합니다.
html {
scroll-behavior: smooth;
}
나를 위해 일한 코드는 다음과 같습니다.
`$('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();
};
});
}
}
});
`