Angular2 Routing con Hashtag per ancorare la pagina

Desidero aggiungere alcuni collegamenti sulla mia pagina Angular2, che quando si fa clic, salterà a posizioni specifiche all’interno di quella pagina, come i normali hashtag. Quindi i collegamenti sarebbero qualcosa di simile

/users/123#userInfo /users/123#userPhoto /users/123#userLikes 

eccetera.

Non penso di aver bisogno di HashLocationStrategy, dato che sto bene con il normale modo Angular2, ma se aggiungo direttamente, il link salterà effettivamente alla radice, non da qualche parte sulla stessa pagina. Qualsiasi direzione è apprezzata, grazie.

Aggiornare

Questo è ora supportato

 Jump to 'Test' anchor  
 this._router.navigate( ['/somepath', id ], {fragment: 'test'}); 

Aggiungi sotto il codice al tuo componente per scorrere

  import {ActivatedRoute} from '@angular/router'; // <-- do not forget to import private fragment: string; constructor(private route: ActivatedRoute) { } ngOnInit() { this.route.fragment.subscribe(fragment => { this.fragment = fragment; }); } ngAfterViewInit(): void { try { document.querySelector('#' + this.fragment).scrollIntoView(); } catch (e) { } } 

Originale

Questo è un problema noto e monitorato all’indirizzo https://github.com/angular/angular/issues/6595

Sebbene la risposta di Günter sia corretta, non copre il “salto verso” la parte del tag di ancoraggio .

Pertanto, in aggiunta a:

 Jump to 'Test' anchor  
 this._router.navigate( ['/somepath', id ], {fragment: 'test'}); 

… nel componente (genitore) in cui è necessario un comportamento “salta a”, aggiungere:

 import { Router, NavigationEnd } from '@angular/router'; class MyAppComponent { constructor(router: Router) { router.events.subscribe(s => { if (s instanceof NavigationEnd) { const tree = router.parseUrl(router.url); if (tree.fragment) { const element = document.querySelector("#" + tree.fragment); if (element) { element.scrollIntoView(true); } } } }); } } 

Si prega di notare che questa è una soluzione alternativa ! Segui questo problema github per gli aggiornamenti futuri. Crediti a Victor Savkin per aver fornito la soluzione!

Un po ‘tardi ma ecco una risposta che ho trovato che funziona:

 Anchor 

E nel componente:

 constructor( private route: ActivatedRoute, private router: Router ) {} onAnchorClick ( ) { this.route.fragment.subscribe ( f => { const element = document.querySelector ( "#" + f ) if ( element ) element.scrollIntoView ( element ) }); } 

Quanto sopra non scorre automaticamente alla vista se si atterra già su una pagina con un’ancora, quindi ho usato la soluzione sopra in my ngInit in modo che potesse funzionare anche con quella:

 ngOnInit() { this.router.events.subscribe(s => { if (s instanceof NavigationEnd) { const tree = this.router.parseUrl(this.router.url); if (tree.fragment) { const element = document.querySelector("#" + tree.fragment); if (element) { element.scrollIntoView(element); } } } }); } 

Assicurati di importare Router, ActivatedRoute e NavigationEnd all’inizio del tuo componente e dovrebbe essere tutto a posto.

fonte

Nessuna delle precedenti risposte ha funzionato per me. In un ultimo disperato tentativo, ho provato nel mio modello:

 From Here 
To Here

Con questo nel mio .ts:

 onClick(){ let x = document.querySelector("#foobar"); if (x){ x.scrollIntoView(); } } 

E funziona come previsto per i collegamenti interni. Questo in realtà non utilizza i tag di ancoraggio in modo che non tocchi affatto l’URL.

Le soluzioni di cui sopra non hanno funzionato per me … Questo l’ha fatto:

Innanzitutto, prepara MyAppComponent per lo scorrimento automatico in ngAfterViewChecked ()

 import { Component, OnInit, AfterViewChecked } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Subscription } from 'rxjs'; @Component( { [...] } ) export class MyAppComponent implements OnInit, AfterViewChecked { private scrollExecuted: boolean = false; constructor( private activatedRoute: ActivatedRoute ) {} ngAfterViewChecked() { if ( !this.scrollExecuted ) { let routeFragmentSubscription: Subscription; // Automatic scroll routeFragmentSubscription = this.activatedRoute.fragment .subscribe( fragment => { if ( fragment ) { let element = document.getElementById( fragment ); if ( element ) { element.scrollIntoView(); this.scrollExecuted = true; // Free resources setTimeout( () => { console.log( 'routeFragmentSubscription unsubscribe' ); routeFragmentSubscription.unsubscribe(); }, 1000 ); } } } ); } } } 

Quindi, passa alla my-app-route inviando prodID hashtag di prodID

 import { Component } from '@angular/core'; import { Router } from '@angular/router'; @Component( { [...] } ) export class MyOtherComponent { constructor( private router: Router ) {} gotoHashtag( prodID: string ) { this.router.navigate( [ '/my-app-route' ], { fragment: prodID } ); } } 

Aggiungendo la risposta di Kalyoyan, questa sottoscrizione è legata al router e continuerà fino a quando la pagina non sarà completamente aggiornata. Quando ti abboni agli eventi del router in un componente, assicurati di annullare l’iscrizione in ngOnDestroy:

 import { OnDestroy } from '@angular/core'; import { Router, NavigationEnd } from '@angular/router'; import { Subscription } from "rxjs/Rx"; class MyAppComponent implements OnDestroy { private subscription: Subscription; constructor(router: Router) { this.subscription = router.events.subscribe(s => { if (s instanceof NavigationEnd) { const tree = router.parseUrl(router.url); if (tree.fragment) { const element = document.querySelector("#" + tree.fragment); if (element) { element.scrollIntoView(element); } } } }); } public ngOnDestroy() { this.subscription.unsubscribe(); } } 

Dopo aver letto tutte le soluzioni, ho cercato un componente e ne ho trovato uno che fa esattamente quello che la domanda originale chiedeva: scorrere verso i collegamenti di ancoraggio. https://www.npmjs.com/package/ng2-scroll-to

Quando lo installi, usi la syntax come:

 // app.awesome.component.ts @Component({ ... template: `... Scroll to main section  

Ha funzionato davvero bene per me.

Poiché la proprietà del frammento non fornisce ancora lo scrolling dell’ancora, questa soluzione alternativa ha fatto il trucco per me:

  

Ho appena ottenuto questo lavoro sul mio sito web, quindi ho pensato che sarebbe valso la pena pubblicare la mia soluzione qui.

 Link Text!  
They're trying to anchor to me!

E poi nel tuo componente, assicurati di includere questo:

  import { ActivatedRoute } from '@angular/router'; constructor(private route: ActivatedRoute) { this.route.fragment.subscribe ( f => { const element = document.querySelector ( "#" + f ) if ( element ) element.scrollIntoView ( element ) }); } 

Una soluzione semplice che funziona per le pagine senza parametri di query, è browser indietro / avanti, router e deep-linking compatibile.

 Go To Anchor 1 ngOnInit() { // If your page is dynamic this.yourService.getWhatever() .then( data => { this.componentData = data; setTimeout(() => this.jumpToId( window.location.hash.substr(1) ), 100); } ); // If your page is static // this.jumpToId( window.location.hash.substr(1) ) } jumpToId( fragment ) { // Use the browser to navigate window.location.hash = fragment; // But also scroll when routing / deep-linking to dynamic page // or re-clicking same anchor if (fragment) { const element = document.querySelector('#' + fragment); if (element) element.scrollIntoView(); } } 

Il timeout è semplicemente per consentire alla pagina di caricare qualsiasi dato dinamico “protetto” da un * ngIf. Questo può anche essere utilizzato per scorrere fino alla parte superiore della pagina quando si cambia rotta: è sufficiente fornire un tag di ancoraggio superiore predefinito.

Tutte le altre risposte funzioneranno su Angular versione <6.1. Ma se hai l'ultima versione, non avrai bisogno di fare questi brutti hack mentre Angular ha risolto il problema.

ecco il link per il rilascio

Tutto quello che devi fare è impostare scrollOffset con l’opzione del secondo argomento del metodo RouterModule.forRoot .

 @NgModule({ imports: [ RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled', anchorScrolling: 'enabled', scrollOffset: [0, 64] // [x, y] }) ], exports: [RouterModule] }) export class AppRoutingModule {} 

Ecco un’altra soluzione con la risposta a JavierFuentes:

 Jump to Element 

in sceneggiatura:

 import {ActivatedRoute} from "@angular/router"; import {Subscription} from "rxjs/Subscription"; export class Links { private scrollExecuted: boolean = false; constructor(private route: ActivatedRoute) {} ngAfterViewChecked() { if (!this.scrollExecuted) { let routeFragmentSubscription: Subscription; routeFragmentSubscription = this.route.fragment.subscribe(fragment => { if (fragment) { let element = document.getElementById(fragment); if (element) { element.scrollIntoView(); this.scrollExecuted = true; // Free resources setTimeout( () => { console.log('routeFragmentSubscription unsubscribe'); routeFragmentSubscription.unsubscribe(); }, 0); } } }); } } gotoHashtag(fragment: string) { const element = document.querySelector("#" + fragment); if (element) element.scrollIntoView(element); } } 

Ciò consente all’utente di scorrere direttamente all’elemento, se l’utente atterra direttamente sulla pagina con hashtag in url.

Ma in questo caso, ho sottoscritto il percorso Fragment in ngAfterViewChecked ma ngAfterViewChecked() viene chiamato continuamente per ogni ngDoCheck e non consente all’utente di scorrere in alto, quindi routeFragmentSubscription.unsubscribe viene chiamato dopo un timeout di 0 millis dopo la visualizzazione è scorrere verso l’elemento.

Inoltre, il metodo gotoHashtag è definito per scorrere fino all’elemento quando l’utente fa clic in modo specifico sul tag di ancoraggio.

Aggiornare:

Se url ha querystrings, [routerLink]="['self-route', id]" in anchor non conserverà le querystring. Ho provato a seguire la soluzione alternativa per lo stesso:

 Jump to Element constructor( private route: ActivatedRoute, private _router:Router) { } ... ... gotoHashtag(fragment: string) { let url = ''; let urlWithSegments = this._router.url.split('#'); if(urlWithSegments.length){ url = urlWithSegments[0]; } window.location.hash = fragment; const element = document.querySelector("#" + fragment); if (element) element.scrollIntoView(element); } 

Ho appena testato il plugin molto utile disponibile in nmp- ngx-scroll-to , che funziona perfettamente per me. Tuttavia è progettato per Angular 4+, ma forse qualcuno troverà utile questa risposta.

Ho provato la maggior parte di queste soluzioni, ma ho riscontrato problemi nell’andare e tornare con un altro frammento che non avrebbe funzionato, quindi ho fatto qualcosa di un po ‘diverso che funziona al 100%, e mi sbarazza del brutto hash nell’URL.

tl; dr, ecco un modo migliore di quello che ho visto finora.

 import { Component, OnInit, AfterViewChecked, OnDestroy } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Subscription } from 'rxjs/Subscription'; @Component({ selector: 'app-hero', templateUrl: './hero.component.html', styleUrls: ['./hero.component.scss'] }) export class HeroComponent implements OnInit, AfterViewChecked, OnDestroy { private fragment: string; fragSub: Subscription; constructor(private route: ActivatedRoute) { } ngOnInit() { this.fragSub = this.route.fragment.subscribe( fragment => { this.fragment = fragment; }) } ngAfterViewChecked(): void { try { document.querySelector('#' + this.fragment).scrollIntoView({behavior: 'smooth'}); window.location.hash = ""; } catch (e) { } } ngOnDestroy() { this.fragSub.unsubscribe(); } } 

Ho avuto lo stesso problema. La soluzione: utilizzando View port Scroller https://angular.io/api/common/ViewportScroller#scrolltoanchor

  lens  

– Codice del componente:

 export class ParametrageComponent { constructor(private viewScroller: ViewportScroller) {} scrollTo(tag : string) { this.viewScroller.scrollToAnchor(tag); } } 

Questo lavoro per me !! Questo ngPer quindi dynamicmente il tag di ancoraggio, è necessario attendere il rendering

HTML:

 
{{cm.namae}} Reply Blah Blah

Il mio file ts:

 private fragment: string; @ViewChildren('ngForComments') AnchorComments: QueryList; ngOnInit() { this.route.fragment.subscribe(fragment => { this.fragment = fragment; }); } ngAfterViewInit() { this.AnchorComments.changes.subscribe(t => { this.ngForRendred(); }) } ngForRendred() { this.jumpToId() } jumpToId() { let x = document.querySelector("#" + this.fragment); console.log(x) if (x){ x.scrollIntoView(); } } 

Non dimenticare di importare ViewChildren , QueryList ecc. E aggiungere qualche costruttore ActivatedRoute !!