Desplácese al elemento al hacer clic en Angular 4

102

Quiero poder desplazarme a un objetivo cuando se presiona un botón. Estaba pensando en algo como esto.

<button (click)="scroll(#target)">Button</button>

Y en mi component.tsmétodo como.

scroll(element) {
    window.scrollTo(element.yPosition)
}

Sé que el código anterior no es válido, solo para mostrar lo que estaba pensando. Acabo de comenzar a aprender Angular 4 sin experiencia previa en Angular. He estado buscando algo como esto, pero todos los ejemplos están en AngularJs, que difiere mucho de Angular 4

BuZZ-dEE
fuente
1
Tu sintaxis no tiene problemas pero necesitas definir qué es #target.
wannadream
1
¿Entonces esto debería funcionar? Cuando uso un número arbitrario y llamo a window.scrollTo (500) en mi función, no sucede nada. Estaba pensando que ese elemento sería un HTMLElement
Bien, sin embargo, ¿qué es #target, Angular no lo resolverá? Puede probar scroll () sin parámetro primero.
wannadream
Sí, intenté (clic) = "scroll ()" en mi botón y window.scrollTo (0, 500) en el componente, pero no pasa nada
2
Pero cuando hago window.scrollTo (0, 500) en el constructor con un retraso de 500ms, funciona

Respuestas:

154

Podrías hacerlo así:

<button (click)="scroll(target)"></button>
<div #target>Your target</div>

y luego en su componente:

scroll(el: HTMLElement) {
    el.scrollIntoView();
}

Editar: Veo comentarios que indican que esto ya no funciona debido a que el elemento no está definido. Creé un ejemplo de StackBlitz en Angular 7 y todavía funciona. ¿Alguien puede dar un ejemplo donde no funciona?

Frank Modica
fuente
Por alguna razón, ejecutar ese código exacto no hace nada por mí. Incluso una window.scrollTo (0, 500) codificada no hace nada
1
@ N15M0_jk Sí, también hay un objeto que puede pasar con otras opciones, dependiendo de lo que necesite. developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
Frank Modica
1
@Anthony Te permite hacer referencia al elemento que quieres pasar a la scrollfunción del componente. Observe que el evento de clic llama scroll(target). Si desea obtener acceso al elemento desde el interior del componente sin tener que pasar el elemento, puede usar @ViewChild.
Frank Modica
2
Funciona bien conmigo ahora. ¡Pero antes cometí un error tonto y usé en id="target"lugar de #targety me dio "el es un error indefinido"!
yashthakkar1173
1
Creo que el error indefinido ocurre si el elemento con el #targetestá dentro de un *ngIf, pero debería funcionar si usa el @ViewChildmétodo en el enlace de @abbastec
espectacularbob
47

En realidad, existe una forma pura de JavaScript de lograr esto sin usar setTimeoutorequestAnimationFrame o jQuery.

En resumen, busque el elemento en scrollView al que desea desplazarse y utilícelo scrollIntoView.

el.scrollIntoView({behavior:"smooth"});

Aquí hay un plunkr .

Jon
fuente
3
2 formas en las que esta respuesta es diferente: 1. Este es un desplazamiento animado suave, no un salto. 2. Esta respuesta no desplaza una ventana, sino que mueve una vista de desplazamiento dentro de una ventana. Por ejemplo, si tiene una vista de desplazamiento horizontal dentro de la ventana. Consulte el plunkr para ver un ejemplo.
Jon
1
scrollIntoViewOptions de scrollIntoView (el objeto como argumento) solo es compatible con Firefox en este momento.
Jesús Fuentes
Funciona bien para Chrome y Firefox, pero no para Safari.
Yamashiro Rion
45

Así es como lo hice usando Angular 4.

Modelo

<div class="col-xs-12 col-md-3">
  <h2>Categories</h2>
  <div class="cat-list-body">
    <div class="cat-item" *ngFor="let cat of web.menu | async">
      <label (click)="scroll('cat-'+cat.category_id)">{{cat.category_name}}</label>
    </div>
  </div>
</div>

agregue esta función al Componente.

scroll(id) {
  console.log(`scrolling to ${id}`);
  let el = document.getElementById(id);
  el.scrollIntoView();
}
LH7
fuente
No ha establecido elementRefs o ID HTML en su plantilla. ¿Dónde está exactamente el elemento 'cat -' + cat.category_id al que te estás desplazando?
Keegan
1
Esta es una mejor respuesta. Puede poner el pergamino en otro componente.
Dale Nguyen
Esta debería ser la respuesta aceptada. Trabajando para Angular 9.
Dieciséis
33

En Angular 7 funciona perfecto

HTML

<button (click)="scroll(target)">Click to scroll</button>
<div #target>Your target</div>

En componente

  scroll(el: HTMLElement) {
    el.scrollIntoView({behavior: 'smooth'});
  }
Robert S.
fuente
2
bonificación por {comportamiento: 'suave'}
Recetas de Squapl
Está funcionando para mí ... gracias especiales por {comportamiento: 'suave'}
Vibhu kumar
Esto no funcionará si #targetse define después del botón, lo cual es relevante si tiene un encabezado flotante, por ejemplo ...
Jonathan
21

Jon tiene la respuesta correcta y esto funciona en mis proyectos angulares 5 y 6.

Si quisiera hacer clic para desplazarse suavemente de la barra de navegación al pie de página:

<button (click)="scrollTo('.footer')">ScrolltoFooter</button>
<footer class="footer">some code</footer>

scrollTo(className: string):void {
   const elementList = document.querySelectorAll('.' + className);
   const element = elementList[0] as HTMLElement;
   element.scrollIntoView({ behavior: 'smooth' });
}

Como quería volver al encabezado desde el pie de página, creé un servicio en el que se encuentra esta función y lo inyecté en los componentes de la barra de navegación y el pie de página y pasé el 'encabezado' o el 'pie de página' cuando fuera necesario. solo recuerde dar a las declaraciones de componentes los nombres de clase utilizados:

<app-footer class="footer"></app-footer>
Stephen E.
fuente
15

Otra forma de hacerlo en Angular:

Margen:

<textarea #inputMessage></textarea>

Agregar ViewChild()propiedad:

@ViewChild('inputMessage')
inputMessageRef: ElementRef;

Desplácese a cualquier lugar que desee dentro del componente usando la scrollIntoView()función:

this.inputMessageRef.nativeElement.scrollIntoView();
Schnapz
fuente
10

Puede desplazarse a cualquier referencia de elemento en su vista utilizando el bloque de código a continuación. Tenga en cuenta que el objetivo (elementref id ) podría estar en cualquier etiqueta html válida.

En la vista (archivo html)

<div id="target"> </div>
<button (click)="scroll()">Button</button>
 

  

en el .tsarchivo,

scroll() {
   document.querySelector('#target').scrollIntoView({ behavior: 'smooth', block: 'center' });
}
Ifesinachi Bryan
fuente
7

Puede lograrlo utilizando la referencia a un elemento DOM angular de la siguiente manera:

Aquí está el ejemplo en stackblitz

la plantilla de componente:

<div class="other-content">
      Other content
      <button (click)="element.scrollIntoView({ behavior: 'smooth', block: 'center' })">
        Click to scroll
      </button>
    </div>
    <div id="content" #element>
      Some text to scroll
</div>
Andrés Gardiol
fuente
6

En Angular puede usar ViewChildy ElementRef: darle a su elemento HTML una referencia

<div #myDiv > 

y dentro de su componente:

import { ViewChild, ElementRef } from '@angular/core';
@ViewChild('myDiv') myDivRef: ElementRef;

que puedes usar this.myDivRef.nativeElementpara llegar a tu elemento

M.Amer
fuente
Esta es una buena solución, pero el problema es que solo funciona cuando recargo la pestaña pero no con routerLink. ¿Alguna solución para este problema chicos?
Ahsan
-8

He hecho algo como lo que estás preguntando simplemente usando jQuery para encontrar el elemento (como document.getElementById(...)) y usando la .focus()llamada.

Kenneth Salomon
fuente
3
¿Es jQuery realmente necesario cuando se usa Angular? Parece que Angular debería ser suficiente
No estoy 100% seguro, pero estaba en un entorno que no ha sido validado y refactorizado para Angular2, así que no busqué demasiado una solución en Angular y simplemente elegí algo a lo que sabía que tendría acceso.
Kenneth Salomon
8
No deberías usar Jquery y Angular
Stefdelec
2
Sí, sí, he aprendido mucho y todos comentan que no debería usar jQuery. No estás diciendo nada que otros no hayan comentado justo encima de ti.
Kenneth Salomon
Te votó a favor por la humildad. Me gustaría agregar que las respuestas de jQuery tienen algún valor para aquellos que están en transición a los marcos de SPA. Mostrando cómo solíamos hacerlo y viendo los comentarios recomendando otras soluciones.
B2K
-17

Puedes hacer esto usando jquery:

código ts:

    scrollTOElement = (element, offsetParam?, speedParam?) => {
    const toElement = $(element);
    const focusElement = $(element);
    const offset = offsetParam * 1 || 200;
    const speed = speedParam * 1 || 500;
    $('html, body').animate({
      scrollTop: toElement.offset().top + offset
    }, speed);
    if (focusElement) {
      $(focusElement).focus();
    }
  }

código HTML :

<button (click)="scrollTOElement('#elementTo',500,3000)">Scroll</button>

Aplique esto en los elementos que desea desplazar:

<div id="elementTo">some content</div>

Aquí hay una muestra de stackblitz.

Gns
fuente
1
Excepto que esta operación está pidiendo que las soluciones de TypeScript no funcionen con un marco obsoleto (votado en contra)
ash
esta es la solución mecanografiada.
Gns
1
No entendió mi punto, su respuesta usa jQuery (podría agregar de la manera más ineficiente) en lugar de simplemente usar ES *. Tus constantes tampoco declaran su tipo. Es solo un mal ejemplo con mala lógica usando jQuery, que no es lo que se preguntó.
Ash