programing

페이지 앵커에 해시태그를 사용한 Angular2 라우팅

bestprogram 2023. 5. 7. 12:05

페이지 앵커에 해시태그를 사용한 Angular2 라우팅

저는 제 Angular2 페이지에 링크를 추가하고 싶습니다. 클릭하면 일반 해시태그가 하는 것처럼 페이지 내의 특정 위치로 이동합니다.그래서 그 링크들은 다음과 같은 것일 것입니다.

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

기타.

일반적인 Angular2 방식으로는 괜찮기 때문에 해시 위치 전략이 필요하지 않다고 생각하지만, 직접 추가하면 링크가 같은 페이지가 아닌 루트로 이동합니다.어떤 지시든 감사합니다.

갱신하다

이제 지원됩니다.

<a [routerLink]="['somepath']" fragment="Test">Jump to 'Test' anchor </a>
this._router.navigate( ['/somepath', id ], {fragment: 'test'});

스크롤할 구성 요소에 아래 코드 추가

  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) { }
  }

원래의

이는 알려진 문제이며 https://github.com/angular/angular/issues/6595 에서 추적됩니다.

답변이 좀 늦어서 죄송합니다;Angular Routing Documentation에는 페이지 앵커에 대한 해시태그를 사용하여 라우팅하는 데 도움이 되는 사전 정의된 기능이 있습니다. 즉, anchorScrolling: 'enabled'.

1단계:- 먼저 app.module.ts 파일에서 라우터 모듈 가져오기:-

imports:[ 
    BrowserModule, 
    FormsModule,
    RouterModule.forRoot(routes,{
      anchorScrolling: 'enabled'
    })
  ],

2단계:- HTML 페이지로 이동하여 네비게이션을 만들고 [routerLink]와 fragment와 같은 두 가지 중요한 속성을 추가하여 각 DivID에 일치시킵니다.

<ul>
    <li> <a [routerLink] = "['/']"  fragment="home"> Home </a></li>
    <li> <a [routerLink] = "['/']"  fragment="about"> About Us </a></li>
  <li> <a [routerLink] = "['/']"  fragment="contact"> Contact Us </a></li>
</ul>

3단계:- ID 이름을 fragment와 일치시켜 section/div를 만듭니다.

<section id="home" class="home-section">
      <h2>  HOME SECTION </h2>
</section>

<section id="about" class="about-section">
        <h2>  ABOUT US SECTION </h2>
</section>

<section id="contact" class="contact-section">
        <h2>  CONTACT US SECTION </h2>
</section>

참고로, 당신의 문제를 해결하는 데 도움이 되는 작은 데모를 만들어 아래 예시를 추가했습니다.

데모: https://routing-hashtag-page-anchors.stackblitz.io/

귄터의 대답이 맞긴 하지만 앵커 태그 부분의 "점프"는 다루지 않습니다.

따라서 다음과 같은 기능을 추가할 수 있습니다.

<a [routerLink]="['somepath']" fragment="Test">Jump to 'Test' anchor </a>
this._router.navigate( ['/somepath', id ], {fragment: 'test'});

"다음으로 이동" 동작이 필요한 구성 요소(상위)에 다음을 추가합니다.

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

  }
}

이것은 해결 방법입니다!나중에 업데이트하려면 이 Github 문제를 따르십시오.솔루션을 제공한 Victor Savkin의 공로를 인정합니다!

조금 늦었지만 제가 찾은 답은 다음과 같습니다.

<a [routerLink]="['/path']" fragment="test" (click)="onAnchorClick()">Anchor</a>

구성 요소:

constructor( private route: ActivatedRoute, private router: Router ) {}

  onAnchorClick ( ) {
    this.route.fragment.subscribe ( f => {
      const element = document.querySelector ( "#" + f )
      if ( element ) element.scrollIntoView ( element )
    });
  }

이미 앵커가 있는 페이지에 착륙하면 위의 내용이 자동으로 보기로 스크롤되지 않으므로 위의 솔루션을 myngInit에서 사용하여 이와 함께 작동할 수 있도록 했습니다.

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

구성 요소의 시작 부분에서 라우터, 활성화된 경로 및 탐색 종료를 가져오십시오. 그러면 모든 것이 좋습니다.

원천

이전의 어떤 대답도 저에게는 통하지 않았습니다.마지막 노력으로 템플릿을 사용해 보았습니다.

<a (click)="onClick()">From Here</a>
<div id='foobar'>To Here</div>

.ts에 있는 경우:

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

그리고 내부 링크에 대해서는 예상대로 작동합니다.이것은 실제로 앵커 태그를 사용하지 않으므로 URL에 전혀 닿지 않습니다.

이러한 요소 ID를 URL에 추가하는 것이 문제가 되지 않는 경우 다음 링크를 검토해야 합니다.

Angular 2 - 현재 페이지의 요소에 대한 앵커 링크

// html
// add (click) event on element
<a (click)="scroll({{any-element-id}})">Scroll</a>

// in ts file, do this
scroll(sectionId) {
let element = document.getElementById(sectionId);

  if(element) {
    element.scrollIntoView(); // scroll to a particular element
  }
 }

위의 해결책은 저에게 효과가 없었습니다.이 사람이 해냈습니다.

저먼준니다합을 준비합니다.MyAppComponentningAfterViewChecked()에서 자동 스크롤하는 경우...

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

              }
            }
          } );
    }

  }

}

다음, 다으로다니이합으로 이동합니다.my-app-route 내기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 } );
  }

}

합니다.app-routing.module.ts:

@NgModule({
  imports: [RouterModule.forRoot(routes, {
    useHash: true,
    scrollPositionRestoration: 'enabled',
    anchorScrolling: 'enabled',
    scrollOffset: [0, 64]
  })],
  exports: [RouterModule]
})

HTML에 포함됩니다.

<a href="#/users/123#userInfo">

html 파일:

<a [fragment]="test1" [routerLink]="['./']">Go to Test 1 section</a>

<section id="test1">...</section>
<section id="test2">...</section>

ints 파일:

export class PageComponent implements AfterViewInit, OnDestroy {

  private destroy$$ = new Subject();
  private fragment$$ = new BehaviorSubject<string | null>(null);
  private fragment$ = this.fragment$$.asObservable();

  constructor(private route: ActivatedRoute) {
    this.route.fragment.pipe(takeUntil(this.destroy$$)).subscribe(fragment => {
      this.fragment$$.next(fragment);
    });
  }

  public ngAfterViewInit(): void {
    this.fragment$.pipe(takeUntil(this.destroy$$)).subscribe(fragment => {
      if (!!fragment) {
        document.querySelector('#' + fragment).scrollIntoView();
      }
    });
  }

  public ngOnDestroy(): void {
    this.destroy$$.next();
    this.destroy$$.complete();
  }
}

다른 모든 답변은 Angular 버전 < 6.1에서 작동합니다.그러나 최신 버전이 있으면 Angular가 문제를 해결했기 때문에 이러한 추악한 해킹을 할 필요가 없습니다.

여기 이슈 링크가 있습니다.

▁all▁set▁you로 설정하기만 하면 됩니다scrollOffset 두 번 주 째 선 택 하 의 을 장 ▁of ▁of ▁option ▁the 의 ▁the ▁with ▁argument 여 하RouterModule.forRoot방법.

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

Kalyoyan의 답변에 덧붙여, 이 구독은 라우터에 연결되어 있으며 페이지가 완전히 새로 고쳐질 때까지 계속됩니다.구성 요소에서 라우터 이벤트를 구독할 때 OnDestroy의 구독을 취소해야 합니다.

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

fragment 속성은 여전히 앵커 스크롤 기능을 제공하지 않기 때문에 이 해결 방법은 유용했습니다.

<div [routerLink]="['somepath']" fragment="Test">
  <a href="#Test">Jump to 'Test' anchor </a>
</div>

제 웹 사이트에서 이 작업을 수행한 지 얼마 되지 않았기 때문에 여기에 제 솔루션을 게시할 가치가 있다고 생각했습니다.

<a [routerLink]="baseUrlGoesHere" fragment="nameOfYourAnchorGoesHere">Link Text!</a>

<a name="nameOfYourAnchorGoesHere"></a>
<div>They're trying to anchor to me!</div>

그런 다음 구성 요소에 다음을 포함해야 합니다.

 import { ActivatedRoute } from '@angular/router';

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

모든 해결책을 읽은 후, 저는 원래 질문이 요구했던 것과 정확히 일치하는 구성 요소를 찾았습니다: 앵커 링크로 스크롤하는 것입니다.https://www.npmjs.com/package/ng2-scroll-to

설치할 때 다음과 같은 구문을 사용합니다.

// app.awesome.component.ts
@Component({
   ...
   template: `...
        <a scrollTo href="#main-section">Scroll to main section</a>
        <button scrollTo scrollTargetSelector="#test-section">Scroll to test section</a>
        <button scrollTo scrollableElementSelector="#container" scrollYTarget="0">Go top</a>
        <!-- Further content here -->
        <div id="container">
            <section id="main-section">Bla bla bla</section>
            <section id="test-section">Bla bla bla</section>
        <div>
   ...`,
})
export class AwesomeComponent {
}

그것은 저에게 정말 잘 작동했습니다.

쿼리 매개 변수가 없는 페이지에 대해 작동하는 간단한 솔루션은 브라우저 뒤로/앞으로, 라우터 및 딥 링크 호환입니다.

<a (click)="jumpToId('anchor1')">Go To Anchor 1</a>


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

시간 초과는 페이지가 *ngIf에 의해 "보호된" 동적 데이터를 로드할 수 있도록 하기 위한 것입니다.경로를 변경할 때 페이지 맨 위로 스크롤하는 데도 사용할 수 있습니다. 기본 상단 앵커 태그만 제공합니다.

다른 답변과 달리 추가로 추가합니다.focus() scrollIntoView()또한 사용하고 있습니다.setTimeout할 때 에 그 , 을 변경한 것 같습니다.setTimeout이 문제를 해결합니다.

출발지:

<a [routerLink] fragment="some-id" (click)="scrollIntoView('some-id')">Jump</a>

대상:

<a id="some-id" tabindex="-1"></a>

유형 스크립트:

scrollIntoView(anchorHash) {
    setTimeout(() => {
        const anchor = document.getElementById(anchorHash);
        if (anchor) {
            anchor.focus();
            anchor.scrollIntoView();
        }
    });
}

저도 같은 문제가 있었습니다.솔루션: View 포트 Scroller 사용 https://angular.io/api/common/ViewportScroller#scrolltoanchor

app-proxy.sys.ts 코드:

import { PageComponent } from './page/page.component';

const routes: Routes = [
   path: 'page', component: PageComponent },
   path: 'page/:id', component: PageComponent }
];

구성 요소 HTML

  <a (click) = "scrollTo('typeExec')">
    <mat-icon>lens</mat-icon>
  </a>

구성 요소 코드:

    import { Component } from '@angular/core';
    import { ViewportScroller } from '@angular/common';


    export class ParametrageComponent {

      constructor(private viewScroller: ViewportScroller) {}

      scrollTo(tag : string)
      {
        this.viewScroller.scrollToAnchor(tag);
      }

    }

하비에르와 관련된 또 다른 해결 방법이 있습니다.푸엔테스는 다음과 같이 대답합니다.

<a [routerLink]="['self-route', id]" fragment="some-element" (click)="gotoHashtag('some-element')">Jump to Element</a>

스크립트:

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

이를 통해 사용자가 직접 URL에 해시태그가 있는 페이지에 착륙할 경우 요소로 직접 스크롤할 수 있습니다.

하지만 이 경우, 저는 루트 프래그먼트를 구독했습니다.ngAfterViewChecked그렇지만ngAfterViewChecked()다음 간격으로 연속적으로 호출됨ngDoCheck그리고 그것은 사용자가 맨 위로 스크롤하는 것을 허용하지 않습니다, 그래서.routeFragmentSubscription.unsubscribe뷰가 요소로 스크롤된 후 0밀리초의 시간 초과 후 호출됩니다.

또한.gotoHashtag메소드는 사용자가 앵커 태그를 클릭할 때 요소로 스크롤하도록 정의됩니다.

업데이트:

url에 쿼리 문자열이 있는 경우[routerLink]="['self-route', id]"닻을 올리면 쿼리 문자열이 보존되지 않습니다.저는 동일한 문제에 대한 해결 방법을 시도했습니다.

<a (click)="gotoHashtag('some-element')">Jump to Element</a>

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

이것은 나에게 효과가 있습니다!!이 ng 태그를 동적으로 고정하려면 렌더링할 때까지 기다려야 합니다.

HTML:

<div #ngForComments *ngFor="let cm of Comments">
    <a id="Comment_{{cm.id}}" fragment="Comment_{{cm.id}}" (click)="jumpToId()">{{cm.namae}} Reply</a> Blah Blah
</div>

마이츠 파일:

private fragment: string;
@ViewChildren('ngForComments') AnchorComments: QueryList<any>;

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

그것을 가져오는 것을 잊지 마세요.ViewChildren,QueryList기타 등등 그리고 생성자를 추가합니다.ActivatedRoute!!

나는 방금 nmp - ngx-scroll-to에서 사용할 수 있는 매우 유용한 플러그인을 테스트했는데, 이것은 나에게 매우 좋습니다.하지만 이것은 Angular 4+용으로 설계되었지만, 아마도 누군가가 이 대답을 유용하게 될 것입니다.

대부분의 솔루션을 시도했지만 다른 조각을 사용하여 왔다 갔다 하는 문제가 발생하여 100% 작동하는 약간 다른 작업을 수행하여 URL의 추한 해시를 제거했습니다.

지금까지 본 것보다 더 좋은 방법이 있습니다.

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

언급URL : https://stackoverflow.com/questions/36101756/angular2-routing-with-hashtag-to-page-anchor