web-dev-qa-db-fra.com

Défilement lisse angular2

Je ne parviens pas à obtenir un service de défilement régulier dans angular. 2. Existe-t-il des services de défilement régulier ou de défilement simple qui pourraient fonctionner jusqu’à ce que l’équipe angular obtienne l’équivalent de $ anchorScroll angular2 travail?

Jusqu'ici je viens d'essayer:

Définition de l'ID incrémental de boucle sur un div parent

[attr.id]="'point' + i"

Appeler un scrollto sur un bouton avec l'id passé

<button 
     type="button" 
     class="btn btn-lg btn-default " 
     (click)="smoothScroll('point'+i)">
           Scroll to point
</button>

Et dans le composant associé, je suis en train de mettre en œuvre une fonction de défilement lisse js simple

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(this.win.scrollTo(0, leapY), timer * speed);
                leapY += step; if (leapY > stopY) leapY = stopY; timer++;
            } return;
        }
        for (var i = startY; i > stopY; i -= step) {
            setTimeout(this.win.scrollTo(0,leapY), timer * speed);
            leapY -= step; if (leapY < stopY) leapY = stopY; timer++;
        }
    }
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;
}

J'essaie également de donner accès à la fenêtre pour le this._win.scrollTo qui provient d'un service de fournisseur de fenêtre

import {Injectable, Provider} from 'angular2/core';
import {window} from 'angular2/src/facade/browser';
import {unimplemented} from 'angular2/src/facade/exceptions';

function _window(): Window {
  return window
}

export abstract class WINDOW {
  get nativeWindow(): Window {
    return unimplemented();
  }
}

class WindowRef_ extends WINDOW {
  constructor() {
    super();
  }
  get nativeWindow(): Window {
    return _window();
  }
}

export const WINDOW_PROVIDERS = [
  new Provider(WINDOW, { useClass: WindowRef_ }),
];

** MODIFIER ---------------------**

J'ai changé le this.win.scrollTo en this.win.window.scrollTo et je reçois maintenant un effet similaire à angular1.x $ anchorscroll où le défilement est rapide au lieu d'une transition en douceur, mais le défilement n'est pas lisse et Je reçois l'erreur d'exception suivante.

Exception error

[~ # ~] met à jour [~ # ~]

Je ne reçois plus cette erreur après avoir découvert que angular2 exécute setTimeout un peu différemment, mais le défilement est toujours instantané et non défilant en douceur.

J'ai changé

  setTimeout(this.win.scrollTo(0, leapY), timer * speed);

à

 setTimeout(() => this.win.scrollTo(0, leapY), timer * speed);
26
Alex J

D'accord, après m'être un peu gratté la tête, voici une solution qui semble bien fonctionner.

Comme auparavant, j'ai déclaré mon identifiant conditionnel et un bouton avec l'appel de fonction scrollTo lorsque l'utilisateur clique dessus.

Maintenant, il n'y a que deux fichiers dans la solution. C'est un service qui vous aidera à retourner la fenêtre de document et le composant du modèle. Rien n’a été modifié dans le service de fenêtre par rapport à l’état ci-dessus, mais je l’inclurai à nouveau dans l’intérêt d’une bonne réponse.

window.service.ts: crier à https://Gist.github.com/lokanx/cc022ee0b8999cd3b7f5 pour aider avec cette pièce

import {Injectable, Provider} from 'angular2/core';
import {window} from 'angular2/src/facade/browser';
import {unimplemented} from 'angular2/src/facade/exceptions';

function _window(): Window {
  return window
}

export abstract class WINDOW {
  get nativeWindow(): Window {
    return unimplemented();
  }
}

class WindowRef_ extends WINDOW {
  constructor() {
    super();
  }
  get nativeWindow(): Window {
    return _window();
  }
}

export const WINDOW_PROVIDERS = [
  new Provider(WINDOW, { useClass: WindowRef_ }),
];

app.component.ts

import { bootstrap } from 'angular2/platform/browser';
import { Component } from 'angular2/core';
import {WINDOW, WINDOW_PROVIDERS} from './window.service';

@Component({
  selector: 'my-app',
  templateUrl: 'app.tpl.html',
  providers: [WINDOW_PROVIDERS]
})

class AppComponent {
    win: Window;
    private offSet: number;
    constructor(
        private _win: WINDOW) { 
        this.win = _win.nativeWindow;
    }
    title = 'Ultra Racing';
    things = new Array(200);

    scrollTo(yPoint: number, duration: number) {
        setTimeout(() => {
            this.win.window.scrollTo(0, yPoint)
        }, duration);
        return;
    }
    smoothScroll(eID) {
        var startY = currentYPosition();
        var stopY = elmYPosition(eID);
        var distance = stopY > startY ? stopY - startY : startY - stopY;
        if (distance < 100) {
            this.win.window.scrollTo(0, stopY); return;
        }
        var speed = Math.round(distance / 100);
        if (speed >= 20) speed = 20;
        var step = Math.round(distance / 100);
        var leapY = stopY > startY ? startY + step : startY - step;
        var timer = 0;
        if (stopY > startY) {
            for (var i = startY; i < stopY; i += step) {
                this.scrollTo(leapY, timer * speed);
                leapY += step; if (leapY > stopY) leapY = stopY; timer++;
            } return;
        }
        for (var i = startY; i > stopY; i -= step) {
            this.scrollTo(leapY, timer * speed);
            leapY -= step; if (leapY < stopY) leapY = stopY; timer++;
        }
    }
}
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;
}

bootstrap(AppComponent)

J'ai créé un plunk pour montrer que cet exemple fonctionne: Exemple de Plunk

16
Alex J

il y a une méthode dans l'objet window appelée scrollTo(). Si vous définissez le comportement sur 'lisse', la page gérera le défilement régulier. exemple (défiler vers le haut de la page):

 window.scrollTo({ left: 0, top: 0, behavior: 'smooth' });

Et avec un exemple de repli:

    try 
    { 
     window.scrollTo({ left: 0, top: 0, behavior: 'smooth' });
     } catch (e) {
      window.scrollTo(0, 0);
      }
32
Mert

Le moyen le plus simple d'y parvenir est d'utiliser ce polyfill: http://iamdustan.com/smoothscroll/

  1. Installez-le en tant que: npm installez smoothscroll-polyfill
  2. Importez-le dans votre fichier polyfill.ts en tant que: require ('smoothscroll-polyfill'). Polyfill ();
  3. Maintenant, vous pouvez utiliser l'option de comportement de scrollIntoView en tant que:

    (document.querySelector ('#' + anchor)). scrollIntoView ({behavior: 'smooth'});

11
Paul Ionescu

Pour tous ceux qui recherchent encore un défilement régulier, la réponse de @ alex-j me convient parfaitement dans Angular 2.0 - mais j’ai dû modifier le service Window en ceci: -

import { Injectable } from '@angular/core';

function _window() : any {
    // return the global native browser window object
    return window;
}

@Injectable()
export class WindowRef {
    get nativeWindow() : any {
        return _window();
    }
}

Tous les accessoires de ce blog http://juristr.com/blog/2016/09/ng2-get-window-ref/ - J'ai maintenant un service de défilement régulier que je peux appeler de n'importe où :)

2
Joe Keene

Si vous voulez un saut d'ancrage très simple qui fonctionne après le routage et dans les vues routées, vous pouvez également utiliser ng2-simple-page-scroll .

<a simplePageScroll href="#myanchor">Go there</a>

Ou juste après le routage:

<a simplePageScroll [routerLink]="['Home']" href="#myanchor">Go there</a>

Il fait un simple saut instantané, mais cela fonctionne.

2
Benny Bottema

exemple:

function goToElement(elemId){
 let element = window.getElementById(elemId);
 element.scrollIntoView({behavior: "smooth"});
}
2
Laxa Tif

j'utilise ce code.

        var dis = distance  ;
        var interval = setInterval(() => {
            this.document.body.scrollTop = dis;
             dis=dis-5 ;
             if (dis<10){
                 clearInterval(interval);
             }
        }, 5);
1
ahmad haeri

Grâce à la réponse acceptée, j'ai pu mettre en place un "défilement vers le haut". Faire défiler vers le haut est en réalité encore plus facile que de faire défiler un élément cible particulier puisque nous faisons toujours défiler vers la position 0. Voici le code:

scrollTo(yPoint: number, duration: number) {
    setTimeout(() => {
        window.scrollTo(0, yPoint)
    }, duration);
    return;
}

smoothScrollToTop() {
    let startY = this.currentYPosition();
    let stopY = 0; // window top
    let distance = stopY > startY ? stopY - startY : startY - stopY;
    if (distance < 100) {
        window.scrollTo(0, stopY);
        return;
    }
    let speed = Math.round(distance / 100);
    let step = speed;
    speed = Math.max(9, speed); //min 9 otherwise it won't look smooth
    let leapY = stopY > startY ? startY + step : startY - step;
    let timer = 0;
    if (stopY > startY) {
        for (let i = startY; i < stopY; i += step) {
            // since setTimeout is asynchronous, the for-loop will will fire all scrolls
            // nearly simoultaniously. Therefore, we need to multiply the speed with
            // a counter which lets the scrolls start with a growing offset which lets the
            // setTimeout wait for a growing time till it scrolls there
            // that way, we prevent the window to scroll instantly to the target Yposition
            this.scrollTo(leapY, timer * speed);
            leapY += step; if (leapY > stopY) leapY = stopY; timer++;
        }
        return;
    } else {
        for (let i = startY; i > stopY; i -= step) {
            this.scrollTo(leapY, timer * speed);
            leapY -= step; if (leapY < stopY) leapY = stopY; timer++;
        }
    }
}

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;
}

Si vous le souhaitez, vous pouvez laisser votre bouton "Défilement vers le haut" apparaître dynamiquement lorsque l'utilisateur fait défiler:

@HostListener('window:scroll', ['$event'])
onWindowScroll(event) {
    this.onScrollFadeInOutScrollToTopButton();
}

shouldShowScrollToTop: boolean = false;

onScrollFadeInOutScrollToTopButton() {
    this.shouldShowScrollToTop = (window.pageYOffset >= window.screen.height/2);
}

Et le code HTML pour le bouton de défilement vers le haut:

<div class="back-to-top">
<button *ngIf="shouldShowScrollToTop" [@fadeInOutTrigger]="animateButtonEntryState" class="mat-primary" md-fab (click)="smoothScrollToTop()">^</button>

Comme vous pouvez le constater, ce bouton possède également un déclencheur d’animation. Vous pouvez penser à utiliser une icône pour le bouton et, idéalement, votre bouton devrait avoir un position:fixed; style.

0
Hans