web-dev-qa-db-fra.com

animation de défilement

Mon code est à http://jsfiddle.net/mannagod/QT3v5/7/ .

Le JS c'est:

function delay() {
    var INTENDED_MONTH = 7 //August
    // INTENDED_MONTH is zero-relative
    now = new Date().getDate(),
rows = document.getElementById('scripture').rows;
    if (new Date().getMonth() != INTENDED_MONTH) {
        // need a value here less than 1, 
        // or the box for the first of the month will be in Red
        now = 0.5
    };
    for (var i = 0, rl = rows.length; i < rl; i++) {
        var cells = rows[i].childNodes;
        for (j = 0, cl = cells.length; j < cl; j++) {
            if (cells[j].nodeName == 'TD'
  && cells[j].firstChild.nodeValue != ''
  && cells[j].firstChild.nodeValue == now) {
                // 'ffff99' // '#ffd700' // TODAY - red
                rows[i].style.backgroundColor = 'red' 
                rows[i].scrollIntoView();
            }
        }
    }
}

J'ai besoin de trouver un moyen de lisser la .scrollintoview(). En ce moment, il "saute" sur la ligne en surbrillance. J'en ai besoin pour passer en douceur à cette ligne. Cela doit être fait dynamiquement en remplacement de scrollintoview. Des idées? Merci.

31
Ted Lederer

Il y a un plugin jQuery exactement pour ça

Voici le lien vers un de mes articles de blog qui décrit le tout et a un lien vers le projet GitHub où vous pouvez obtenir le plugin.

Plugin jQuery scrollintoview() animé.

2
Robert Koritnik

Dans la plupart des navigateurs modernes ( Chrome et Firefox, mais pas Safari, UC ou IE ), vous pouvez passer des options dans un objet à .scrollIntoView().

Essaye ça:

Elm.scrollIntoView({ behavior: 'smooth', block: 'center' })

Les autres valeurs sont behavior: 'instant' ou block: 'start' ou block: 'end'. Voir https://developer.mozilla.org/en/docs/Web/API/Element/scrollIntoView

60
Chris78

Je cherchais également ce problème et j'ai trouvé cette solution:

$('html, body').animate({
    scrollTop: $("#elementId").offset().top
}, 1000);

ressource: http://www.abeautifulsite.net/smoothly-scroll-to-an-element-without-a-jquery-plugin-2/

31
Sarkhan

Peut-être que vous ne voulez pas ajouter jQuery uniquement pour implémenter cette fonctionnalité. elem est l'élément à faire défiler. La position de destination peut être extraite de la propriété offsetTop de l'élément à déplacer dans la vue.

function Scroll_To(elem, pos)
{
    var y = elem.scrollTop;
    y += (pos - y) * 0.3;
    if (Math.abs(y-pos) < 2)
    {
        elem.scrollTop = pos;
        return;
    }
    elem.scrollTop = y;
    setTimeout(Scroll_To, 40, elem, pos);   
}
13
Klaus Heyne

Défilement fluide en utilisant requestAnimationFrame sur une durée spécifique sans jQuery.

Démo: http://codepen.io/Shadeness/pen/XXyvKG?editors=001

window.bringIntoView_started = 0;
window.bringIntoView_ends = 0;
window.bringIntoView_y = 0;
window.bringIntoView_tick = function() {
  var distanceLeft, dt, duration, t, travel;
  t = Date.now();
  if (t < window.bringIntoView_ends) {
    dt = t - window.bringIntoView_started;
    duration = window.bringIntoView_ends - window.bringIntoView_started;
    distanceLeft = window.bringIntoView_y - document.body.scrollTop;
      travel = distanceLeft * (dt / duration);
      document.body.scrollTop += travel;
      window.requestAnimationFrame(window.bringIntoView_tick);
  } else {
    document.body.scrollTop = window.bringIntoView_y;
  }
};
window.bringIntoView = function(e, duration) {
  window.bringIntoView_started = Date.now();
  window.bringIntoView_ends = window.bringIntoView_started + duration;
  window.bringIntoView_y = Math.min(document.body.scrollTop + e.getBoundingClientRect().top, document.body.scrollHeight - window.innerHeight);
  window.requestAnimationFrame(window.bringIntoView_tick);
};

Par exemple:

bringIntoView(document.querySelector('#bottom'), 400)

Elle devrait s'accélérer à mesure que dt (deltaTime) grossit et ralentit à mesure que distanceLeft devient plus petit. J'ai envisagé de rompre la boucle si l'utilisateur faisait défiler mais meh. Les variables globales empêchent l'appel précédent de prendre complètement le relais, mais n'annulent pas la boucle récursive précédente, de sorte qu'elle s'animera deux fois plus rapidement.

7
Zren

Il vous suffit d'inclure ce polyfill et cela fonctionne.

https://github.com/iamdustan/smoothscroll

<script src="js/smoothscroll.js"></script>

Ou exigez-le si vous utilisez npm.

require('smoothscroll-polyfill').polyfill();

Utilisez la méthode native scrollIntoView.

document.getElementById('parallax-group-logo').scrollIntoView({
    block: "start",
    behavior: "smooth"
});
3
Ilario Engler

Essaye ça:

function scroll_into_view_smooth(elem)
{   var FPS = 48; // frames per second
    var DURATION = 0.6; // sec
    var e = elem;
    var left = e.offsetLeft;
    var top = e.offsetTop;
    var width = e.offsetWidth;
    var height = e.offsetHeight;
    var body = document.body;
    var to_scroll = [];
    var p, offset;
    while ((p = e.offsetParent))
    {   var client_width = p.clientWidth;
        var client_height = p!=body ? p.clientHeight : Math.min(document.documentElement.clientHeight, window.innerHeight);
        if (client_width<p.scrollWidth-1 && ((offset=left-p.scrollLeft)<0 || (offset=left+width-p.scrollLeft-client_width)>0))
        {   to_scroll.Push({elem: p, prop: 'scrollLeft', from: p.scrollLeft, offset: offset});
        }
        if (client_height<p.scrollHeight-1 && ((offset=top-p.scrollTop)<0 || (offset=top+height-p.scrollTop-client_height)>0))
        {   to_scroll.Push({elem: p, prop: 'scrollTop', from: p.scrollTop, offset: offset});
        }
        e = p;
        left += e.offsetLeft;
        top += e.offsetTop;
    }
    var x = 0;
    function apply()
    {   x = Math.min(x+1/(DURATION * FPS), 1);
        for (var i=to_scroll.length-1; i>=0; i--)
        {   to_scroll[i].elem[to_scroll[i].prop] = to_scroll[i].from + to_scroll[i].offset*x*x;
        }
        if (x < 1)
        {   setTimeout(apply, 1000/FPS);
        }
    }
    apply();
}
2
jeremiah

Juste pour ajouter à cela au cas où cela aiderait quelqu'un,

Je travaillais sur un PWA pour iOS et Android et j'utilisais la méthode scrollIntoView() jusqu'à ce que je découvre que l'objet scrollIntoViewOptions n'était pas pris en charge par Safari et donc ne ferait pas défiler en douceur ou quoi que ce soit, etc.

J'ai pu imiter la fonctionnalité de scrollIntoView, avec un défilement fluide et une option "la plus proche", pour iOS avec JS ordinaire ... enfin, TypeScript simple ...

Cliquez sur gestionnaire ou w/e:

const element = *elementToScrollIntoView*;
const scrollLayer = *layerToDoTheScrolling*

if (/iPad|iPhone|iPod/.test(navigator.userAgent) {
    let position;
    const top = element.offsetTop - scrollLayer.scrollTop;
    if (element.offsetTop < scrollLayer.scrollTop) {
            // top of element is above top of view - scroll to top of element
        position = element.offsetTop;
    } else if (element.scrollHeight + top < scrollLayer.offsetHeight) {
            // element is in view - don't need to scroll
        return;
    } else if (element.scrollHeight > scrollLayer.offsetHeight) {
            // element is bigger than view - scroll to top of element
        position = element.offsetTop;
    } else {
            // element partially cut-off - scroll remainder into view
        const difference = scrollLayer.offsetHeight - (element.scrollHeight + top);
        position = scrollLayer.scrollTop - difference;
    }
        // custom function for iOS
    scrollToElement(scrollLayer, position, 200);
} else {
        // just use native function for Android
    element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' });
}

Fonction de défilement manuel:

scrollToElement(scrollLayer, destination, duration) {
    if (duration <= 0) {
        return;
    }
    const difference = destination - scrollLayer.scrollTop;
    const perTick = (difference / duration) * 10;

    setTimeout(() => {
        scrollLayer.scrollTop = scrollLayer.scrollTop + perTick;
        if (scrollLayer.scrollTop === destination) {
            return;
        }
        scrollToElement(scrollLayer, destination, duration - 10);
    }, 10);
}

REMARQUE: Le grand si imbriqué et les calculs dans le gestionnaire consistent simplement à trouver la position "la plus proche" alors que j'essayais de reproduire ce comportement, mais en utilisant simplement la fonction scrollToElement pour animer le défilement vers le haut (comportement par défaut sans objet Options), vous pouvez utiliser:

scrollToElement(scrollLayer, element.offsetTop, 200);
1
HazeyAce