Desplazamiento liso angular2


Estoy teniendo problemas para conseguir un servicio de desplazamiento suave para trabajar en angular 2. ¿Hay algún servicio para desplazamiento suave, o desplazamiento de anclaje simple, que pueda funcionar hasta que el equipo de angular 2 consiga el equivalente anchor anchorScroll angular2?

Hasta ahora he intentado:

Configuración * ngFor loop incremental id en un div padre

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

Llamando a un scrollto en un botón con el id pasado

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

Y en el componente asociado estoy tratando de implementar un función de desplazamiento suave de js

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

También estoy tratando de dar acceso a la ventana para el esto._ganar.scrollTo que viene de un servicio de proveedor de ventanas

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_ }),
];

** EDITAR ---------------------**

Cambié esto.ganar.Desplázate a esto.ganar.ventana.scrollTo y ahora estoy obteniendo un efecto similar a angular1.x anchor anchorscroll donde el desplazamiento es rápido en lugar de una transición suave, pero el desplazamiento no es suave y estoy recibiendo la siguiente excepción error.

Error de excepción

ACTUALIZACIÓN

Ya no recibo ese error después de descubrir que angular2 está haciendo el setTimeout un poco diferente, pero el desplazamiento sigue siendo instantáneo y no es un desplazamiento suave.

Cambié

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

A

 setTimeout(() => this.win.scrollTo(0, leapY), timer * speed);
Author: Vel, 2016-03-18

9 answers

Hay un método en el objeto window llamado scrollTo(). Si establece el comportamiento en 'suavizar', la página manejará el desplazamiento suave. ejemplo (desplácese hasta la parte superior de la página):

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

Y con un ejemplo alternativo:

    try 
    { 
     window.scrollTo({ left: 0, top: 0, behavior: 'smooth' });
     } catch (e) {
      window.scrollTo(0, 0);
      }
 22
Author: Mert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-01 10:04:34

Bien, después de rascarme la cabeza un poco, aquí hay una solución que parece estar funcionando bien.

Igual que antes, declaré mi id condicional y un botón con la llamada a la función scrollTo al hacer clic.

Ahora, solo hay dos archivos en la solución es un servicio que ayudará a devolver la ventana del documento y el componente de la plantilla. Nada fue cambiado en el servicio de ventanas del estado anterior, pero lo incluiré de nuevo por el bien de una buena respuesta.

Ventana.Servicio.ts: grita a https://gist.github.com/lokanx/cc022ee0b8999cd3b7f5 por ayudar con esta pieza

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.componente.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)

He creado un plunk para mostrar este ejemplo funcionando: Ejemplo de Plunk

 16
Author: Alex J,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-18 23:07:14

La forma más fácil de lograr esto es mediante el uso de este polyfill: http://iamdustan.com/smoothscroll /

  1. Instalarlo como: npm instalar smoothscroll-polyfill
  2. Impórtalo en tu polyfill.archivo ts como: require('smoothscroll-polyfill').polyfill ();
  3. Ahora puede usar la opción de comportamiento de scrollIntoView como:

    (documento.querySelector ('#'+anchor)).scrollIntoView({ comportamiento: 'suave' });

 10
Author: Paul Ionescu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-23 17:18:56

Si desea un salto de anclaje muy simple que funcione después del enrutamiento y dentro de las vistas enrutadas, también puede usar ng2-simple-page-scroll.

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

O justo después del enrutamiento:

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

Hace un simple salto instantáneo, pero funciona.

 2
Author: Benny Bottema,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-20 20:31:13

Para cualquiera que todavía esté en la búsqueda de un desplazamiento suave @alex-la respuesta de j funciona muy bien para mí en Angular 2.0, pero tuve que cambiar el servicio de ventanas a esto: -

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

Todos los accesorios de este blog http://juristr.com/blog/2016/09/ng2-get-window-ref / - ahora tengo un servicio de desplazamiento suave que puedo llamar desde cualquier lugar:)

 2
Author: Joe Keene,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-28 07:39:36

Utilizo este código .

        var dis = distance  ;
        var interval = setInterval(() => {
            this.document.body.scrollTop = dis;
             dis=dis-5 ;
             if (dis<10){
                 clearInterval(interval);
             }
        }, 5);
 1
Author: ahmad haeri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-15 23:24:08

Ejemplo:

function goToElement(elemId){
 let element = window.getElementById(elemId);
 element.scrollIntoView({behavior: "smooth"});
}
 1
Author: Laxa Tif,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-18 13:26:25

Gracias a la respuesta aceptada pude implementar un "scroll to top"suave. Desplazarse hasta la parte superior es incluso más fácil que desplazarse hasta un elemento objetivo en particular, ya que siempre nos desplazamos hasta la posición 0. Aquí está el código:

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 quieres, puedes dejar que tu botón "Scroll-To-Top" aparezca dinámicamente cuando el usuario se desplace:

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

shouldShowScrollToTop: boolean = false;

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

Y el HTML para el botón de desplazamiento hacia arriba:

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

Como puedes ver, ese botón también tiene una animación desencadenar. Puedes pensar en usar un icono para el botón e idealmente, tu botón debería tener un estilo position:fixed;.

 0
Author: Hans,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-30 12:44:45

Hay otro enfoque, que debe ser considerado: usar jQuery.

Tal vez no es tan elegante como las soluciones nativas, pero muy fácil y funciona perfectamente.

En su índice.html tienes que añadir esto al final del cuerpo:

<script
src="https://code.jquery.com/jquery-3.1.1.min.js"
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
crossorigin="anonymous"></script>

<script>
  $(document).on("click", "a[href*='#']:not([href='#'])", function() {
    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) {
          $('html, body').animate({
          scrollTop: target.offset().top - 100
          }, 1000);
          return false;
      }
    }
  });

</script>

Y ahora puedes usar la simple navegación <a href("#section")> así:

<a href="#section2">Link</a>

También funciona con enrutamiento:

<a class="btn" role="button" routerLink="/contact" fragment="contact_form">Contact us!</a>
 -2
Author: Ábó Szilágyi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-29 09:59:57