Faites défiler jusqu'à l'élément en cliquant dans Angular 4

101

Je veux pouvoir faire défiler jusqu'à une cible lorsqu'un bouton est enfoncé. Je pensais à quelque chose comme ça.

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

Et dans ma component.tsméthode comme.

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

Je sais que le code ci-dessus n'est pas valide mais juste pour montrer ce que je pensais. Je viens de commencer à apprendre Angular 4 sans aucune expérience préalable d'Angular. J'ai cherché quelque chose comme ça mais tous les exemples sont dans AngularJs qui diffère beaucoup d'Angular 4

BuZZ-dEE
la source
1
Votre syntaxe ne pose aucun problème mais vous devez définir ce qu'est #target.
wannadream
1
Alors ça devrait marcher? Lorsque j'utilise un nombre arbitraire et que j'appelle window.scrollTo (500) dans ma fonction, rien ne se passe. Je pensais que cet élément serait un HTMLElement
Bien, cependant, qu'est-ce que #target, Angular ne le résoudra pas? Vous pouvez d'abord tester scroll () sans paramètre.
wannadream
Ouais j'ai essayé (click) = "scroll ()" dans mon bouton et window.scrollTo (0, 500) dans le composant mais rien ne se passe
2
Mais quand je fais window.scrollTo (0, 500) dans le constructeur avec un retard de 500 ms, cela fonctionne

Réponses:

152

Vous pouvez le faire comme ceci:

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

puis dans votre composant:

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

Edit: Je vois des commentaires indiquant que cela ne fonctionne plus car l'élément n'est pas défini. J'ai créé un exemple StackBlitz dans Angular 7 et cela fonctionne toujours. Quelqu'un peut-il donner un exemple où cela ne fonctionne pas?

Frank Modica
la source
Pour une raison quelconque, exécuter ce code exact ne fait rien pour moi. Même une fenêtre codée en dur.scrollTo (0, 500) ne fait rien
1
@ N15M0_jk Oui, il y a aussi un objet que vous pouvez passer avec d'autres options, selon ce dont vous avez besoin. developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
Frank Modica
1
@Anthony Il vous permet de référencer l'élément que vous souhaitez passer à la scrollfonction sur le composant. Notez que l'événement de clic appelle scroll(target). Si vous souhaitez accéder à l'élément depuis l'intérieur du composant sans avoir à passer l'élément, vous pouvez utiliser @ViewChild.
Frank Modica
2
Cela fonctionne bien avec moi maintenant. Mais avant, j'ai fait une erreur stupide et utilisé à la id="target"place de #targetet cela m'a donné "el est une erreur indéfinie"!
yashthakkar1173
1
Je pense que l'erreur non définie se produit si l'élément avec le #targetest à l'intérieur d'un *ngIf, mais cela devrait fonctionner si vous utilisez la @ViewChildméthode dans le lien de @abbastec
spectaculairebob
46

Il existe en fait un moyen purement javascript pour y parvenir sans utiliser setTimeoutou requestAnimationFrameou jQuery.

En bref, recherchez l'élément dans le scrollView vers lequel vous souhaitez faire défiler et utilisez scrollIntoView.

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

Voici un plunkr .

Jon
la source
2
2 façons dont cette réponse est différente: 1. Il s'agit d'un défilement fluide animé, pas d'un saut. 2. Cette réponse ne fait pas défiler une fenêtre, mais déplace une vue de défilement dans une fenêtre. Par exemple, si vous avez une vue de défilement horizontale dans la fenêtre. Vérifiez le plunkr pour un exemple.
Jon
1
scrollIntoViewOptions de scrollIntoView (l'objet comme argument) n'est compatible qu'avec Firefox pour le moment.
Jesús Fuentes
Fonctionne bien pour Chrome et Firefox, mais pas pour Safari.
Yamashiro Rion
45

Voici comment je l'ai fait en utilisant Angular 4.

Modèle

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

ajoutez cette fonction au composant.

scroll(id) {
  console.log(`scrolling to ${id}`);
  let el = document.getElementById(id);
  el.scrollIntoView();
}
LH7
la source
Vous n'avez pas défini d'élémentRefs ou d'identifiants HTML dans votre modèle. Où se trouve exactement l'élément 'cat -' + cat.category_id vers lequel vous faites défiler?
Keegan
1
C'est une meilleure réponse. Vous pouvez placer le parchemin vers un autre composant.
Dale Nguyen
Cela devrait être la réponse acceptée. Working for Angular 9.
Seize
33

Dans Angular 7 fonctionne parfaitement

HTML

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

Dans le composant

  scroll(el: HTMLElement) {
    el.scrollIntoView({behavior: 'smooth'});
  }
Robert S.
la source
2
bonus pour {behavior: 'smooth'}
Recettes Squapl
Cela fonctionne pour moi .. merci tout spécial pour {behavior: 'smooth'}
Vibhu kumar
Cela ne fonctionnera pas si #targetest défini après le bouton, ce qui est pertinent si vous avez un en-tête flottant par exemple ...
Jonathan
21

Jon a la bonne réponse et cela fonctionne dans mes projets angulaires 5 et 6.

Si je voulais cliquer pour faire défiler en douceur de la barre de navigation au pied de page:

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

Parce que je voulais revenir à l'en-tête du pied de page, j'ai créé un service dans lequel se trouve cette fonction et je l'ai injecté dans les composants de la barre de navigation et du pied de page et passé dans `` en-tête '' ou `` pied de page '' si nécessaire. n'oubliez pas de donner aux déclarations des composants les noms de classe utilisés:

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

Une autre façon de le faire dans Angular:

Balisage:

<textarea #inputMessage></textarea>

Ajouter une ViewChild()propriété:

@ViewChild('inputMessage')
inputMessageRef: ElementRef;

Faites défiler n'importe où dans le composant à l'aide de la scrollIntoView()fonction:

this.inputMessageRef.nativeElement.scrollIntoView();
Schnapz
la source
10

Vous pouvez faire défiler jusqu'à n'importe quelle référence d'élément sur votre vue en utilisant le bloc de code ci-dessous. Notez que la cible (elementref id ) peut se trouver sur n'importe quelle balise HTML valide.

Sur la vue (fichier html)

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

  

sur le .tsdossier,

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

Vous pouvez y parvenir en utilisant la référence à un élément DOM angulaire comme suit:

Voici l'exemple dans stackblitz

le modèle de composant:

<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
la source
6

Dans Angular, vous pouvez utiliser ViewChildet ElementRef: donner à votre élément HTML une référence

<div #myDiv > 

et à l'intérieur de votre composant:

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

vous pouvez utiliser this.myDivRef.nativeElementpour accéder à votre élément

M.Amer
la source
C'est une bonne solution, mais le problème est que cela ne fonctionne que lorsque je recharge l'onglet mais pas avec routerLink. Une solution à ce problème les gars?
Ahsan
-8

J'ai fait quelque chose comme ce que vous demandez simplement en utilisant jQuery pour trouver l'élément (tel que document.getElementById(...)) et en utilisant l' .focus()appel.

Kenneth Salomon
la source
3
Est-ce que jQuery est vraiment nécessaire lors de l'utilisation d'Angular? On dirait qu'Angular devrait suffire
Pas sûr à 100% mais j'étais dans un environnement qui n'a pas été validé et refactorisé pour Angular2 donc je n'ai pas cherché trop dur pour une solution dans Angular et je suis simplement allé avec quelque chose auquel je savais que j'aurais accès.
Kenneth Salomon
8
Vous ne devriez pas utiliser Jquery et Angular
Stefdelec
2
Oui oui, j'ai beaucoup appris et tout le monde dit que je ne devrais pas utiliser jQuery. Vous ne dites rien que les autres n'aient pas commenté juste au-dessus de vous.
Kenneth Salomon
Vous a voté pour l'humilité. Je voudrais ajouter que les réponses jQuery ont une certaine valeur pour ceux qui passent aux frameworks SPA. En montrant comment nous le faisions et en voyant les commentaires recommandant d'autres solutions.
B2K
-17

Vous pouvez le faire en utilisant jquery:

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

Code HTML :

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

Appliquez ceci sur les éléments que vous souhaitez faire défiler:

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

Voici un exemple de stackblitz.

GNS
la source
1
Sauf que cette opération demande des solutions TypeScript qui ne fonctionnent pas avec un cadre obsolète (voté à la baisse)
ash
c'est une solution dactylographiée.
Gns
1
Vous avez manqué mon point, votre réponse utilise jQuery (puis-je ajouter de la manière la plus inefficace) plutôt que d'utiliser simplement ES *. Vos constantes ne déclarent pas non plus leur type. C'est juste un mauvais exemple avec une mauvaise logique utilisant jQuery qui n'est pas ce qui a été demandé.
ash