Płynne przewijanie do określonego elementu DIV po kliknięciu


94

Próbuję zrobić to tak, aby po kliknięciu przycisku przewijał się (płynnie) w dół do określonego elementu div na stronie.

Potrzebuję tego, że jeśli klikniesz przycisk, płynnie przewinie się do „sekundy” div.

.first {
    width: 100%;
    height: 1000px;
    background: #ccc;
}

.second {
    width: 100%;
    height: 1000px;
    background: #999;
}
<div class="first"><button type="button">Click Me!</button></div>
<div class="second">Hi</div>


Możesz wypróbować tę wtyczkę, chociaż ta jest znacznie bardziej przyjazna dla użytkownika. Wystarczy, że połączysz plik JS w nagłówku i odpowiednio zmienisz znaczniki, aby działał.
joshrathke

Odpowiedzi:


178

zrobić:

$("button").click(function() {
    $('html,body').animate({
        scrollTop: $(".second").offset().top},
        'slow');
});

Zaktualizowano Jsfiddle


Czy używasz tutaj javaScript czy jQuery?

1
@FahadUddin jego jQuery.
Sudhir Bastakoti,

@SudhirBastakoti: Dlaczego JsFiddle nie umieścił biblioteki jquery na tej stronie?

@Sudhir Bastakoti, ale wielu użytkowników skarży się, że nie jest to płynne przewijanie.
Maulik

40

Istnieje wiele przykładów płynnego przewijania przy użyciu bibliotek JS, takich jak jQuery, Mootools, Prototype itp.

Poniższy przykład dotyczy czystego JavaScript. Jeśli nie masz jQuery / Mootools / Prototype na stronie lub nie chcesz przeładowywać strony ciężkimi bibliotekami JS, przykład będzie pomocny.

http://jsfiddle.net/rjSfP/

Część HTML:

<div class="first"><button type="button" onclick="smoothScroll(document.getElementById('second'))">Click Me!</button></div>
<div class="second" id="second">Hi</div>

Część CSS:

.first {
    width: 100%;
    height: 1000px;
    background: #ccc;
}

.second {
    width: 100%;
    height: 1000px;
    background: #999;
}

Część JS:

window.smoothScroll = function(target) {
    var scrollContainer = target;
    do { //find scroll container
        scrollContainer = scrollContainer.parentNode;
        if (!scrollContainer) return;
        scrollContainer.scrollTop += 1;
    } while (scrollContainer.scrollTop == 0);

    var targetY = 0;
    do { //find the top of target relatively to the container
        if (target == scrollContainer) break;
        targetY += target.offsetTop;
    } while (target = target.offsetParent);

    scroll = function(c, a, b, i) {
        i++; if (i > 30) return;
        c.scrollTop = a + (b - a) / 30 * i;
        setTimeout(function(){ scroll(c, a, b, i); }, 20);
    }
    // start scrolling
    scroll(scrollContainer, scrollContainer.scrollTop, targetY, 0);
}

Używam tego i działa świetnie. Jak jednak spowolnić przewijanie?
jamescampbell

Masz jakiś pomysł, jak dodać przesunięcie dla stałego paska nawigacyjnego w tym kodzie? Oto przykład, który zrobiłem na skrzypcach
Plavookac

3
Nadal pomocny po 5 latach
Owaiz Yusufi

9

Bawiłem się trochę odpowiedzią nico i poczułem się nerwowo. Zrobiłem trochę badania i odkryłem, window.requestAnimationFramektóra jest funkcją, która jest wywoływana w każdym cyklu ponownego malowania. Pozwala to na bardziej przejrzystą animację. Nadal próbuję doskonalić dobre wartości domyślne dla rozmiaru kroku, ale dla mojego przykładu rzeczy wyglądają całkiem dobrze przy użyciu tej implementacji.

var smoothScroll = function(elementId) {
    var MIN_PIXELS_PER_STEP = 16;
    var MAX_SCROLL_STEPS = 30;
    var target = document.getElementById(elementId);
    var scrollContainer = target;
    do {
        scrollContainer = scrollContainer.parentNode;
        if (!scrollContainer) return;
        scrollContainer.scrollTop += 1;
    } while (scrollContainer.scrollTop == 0);

    var targetY = 0;
    do {
        if (target == scrollContainer) break;
        targetY += target.offsetTop;
    } while (target = target.offsetParent);

    var pixelsPerStep = Math.max(MIN_PIXELS_PER_STEP,
                                 (targetY - scrollContainer.scrollTop) / MAX_SCROLL_STEPS);

    var stepFunc = function() {
        scrollContainer.scrollTop =
            Math.min(targetY, pixelsPerStep + scrollContainer.scrollTop);

        if (scrollContainer.scrollTop >= targetY) {
            return;
        }

        window.requestAnimationFrame(stepFunc);
    };

    window.requestAnimationFrame(stepFunc);
}

1
@Alfonso Patrz wyżej. To jest po prostu zoptymalizowana wersja kodu nico w poprzedniej odpowiedzi.
Ned Rockson

@NedRockson Nie działa dla mnie wyświetla komunikat konsoli „Uncaught TypeError: Cannot read property 'parentNode' of null”, ale kod nico działa, co mam zrobić, aby zastosować czystą animację?
Kartik Watwani

@KartikWatwani Oznacza to, że w czytaniu wiersza scrollContainer = scrollContainer.parentNodescrollContainer ma wartość null. Prawdopodobnie oznacza to, że elementIdwywołując tę ​​funkcję, nie przekazujesz poprawnego wyniku. Możliwe jest również, że uruchamiasz ten skrypt na stronie, na której ten elementId nie istnieje.
Ned Rockson

@NedRockson Gdyby elementIdbyło źle, otrzymałbym ten sam błąd w przypadku przykładu @nico, ale w tym przypadku przewijanie działa, ale nie płynnie.
Kartik Watwani

Używanie requestAnimationFramezamiast setTimeoutto najlepszy sposób. setTimeoutnie powinny być używane do animacji.
tsnkff


2

Wziąłem wersję Neda Rocksona i dostosowałem ją tak, aby umożliwiała również przewijanie w górę.

var smoothScroll = function(elementId) {
  var MIN_PIXELS_PER_STEP = 16;
  var MAX_SCROLL_STEPS = 30;
  var target = document.getElementById(elementId);
  var scrollContainer = target;
  do {
    scrollContainer = scrollContainer.parentNode;
    if (!scrollContainer) return;
    scrollContainer.scrollTop += 1;
  } while (scrollContainer.scrollTop === 0);

  var targetY = 0;
  do {
    if (target === scrollContainer) break;
    targetY += target.offsetTop;
  } while (target = target.offsetParent);

  var pixelsPerStep = Math.max(MIN_PIXELS_PER_STEP,
    Math.abs(targetY - scrollContainer.scrollTop) / MAX_SCROLL_STEPS);

  var isUp = targetY < scrollContainer.scrollTop;

  var stepFunc = function() {
    if (isUp) {
      scrollContainer.scrollTop = Math.max(targetY, scrollContainer.scrollTop - pixelsPerStep);
      if (scrollContainer.scrollTop <= targetY) {
        return;
      }
    } else {
        scrollContainer.scrollTop = Math.min(targetY, scrollContainer.scrollTop + pixelsPerStep);

      if (scrollContainer.scrollTop >= targetY) {
        return;
      }
    }

    window.requestAnimationFrame(stepFunc);
  };

  window.requestAnimationFrame(stepFunc);
};


0

Ned Rockson w zasadzie odpowiada na to pytanie. Jednak w jego rozwiązaniu jest fatalna wada. Gdy docelowy element znajduje się bliżej dołu strony niż viewport-height, funkcja nie osiąga instrukcji wyjścia i zatrzymuje użytkownika na dole strony. Można to po prostu rozwiązać, ograniczając liczbę iteracji.

var smoothScroll = function(elementId) {
    var MIN_PIXELS_PER_STEP = 16;
    var MAX_SCROLL_STEPS = 30;
    var target = document.getElementById(elementId);
    var scrollContainer = target;
    do {
        scrollContainer = scrollContainer.parentNode;
        if (!scrollContainer) return;
        scrollContainer.scrollTop += 1;
    } while (scrollContainer.scrollTop == 0);

    var targetY = 0;
    do {
        if (target == scrollContainer) break;
        targetY += target.offsetTop;
    } while (target = target.offsetParent);

    var pixelsPerStep = Math.max(MIN_PIXELS_PER_STEP,
                                 (targetY - scrollContainer.scrollTop) / MAX_SCROLL_STEPS);

    var iterations = 0;
    var stepFunc = function() {
        if(iterations > MAX_SCROLL_STEPS){
            return;
        }
        scrollContainer.scrollTop =
            Math.min(targetY, pixelsPerStep + scrollContainer.scrollTop);

        if (scrollContainer.scrollTop >= targetY) {
            return;
        }

        window.requestAnimationFrame(stepFunc);
    };

    window.requestAnimationFrame(stepFunc);
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.