私のAngular 2ページにリンクを追加したいのですが、クリックすると特定の位置にジャンプしますwithin通常のハッシュタグのように。そのため、リンクは次のようになります。
/users/123#userInfo
/users/123#userPhoto
/users/123#userLikes
等.
通常のAngular 2の方法で問題ないので、HashLocationStrategyは必要ないと思いますが、直接追加すると、リンクは実際には同じページのどこかではなくルートにジャンプします。どんな方向でも感謝します。
更新
これは現在サポートされています
<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 で追跡されています。
Günter'sanswer は正しいですが、アンカータグ部分への「ジャンプ」はカバーしません。
したがって、さらに:
<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 )
});
}
アンカー付きのページにすでに着地している場合、上記は自動的にビューにスクロールすることはありません。そのため、ngInitで上記の解決策を使用しました。
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); }
}
}
});
}
あなたのコンポーネントの最初に必ずRouter、ActivatedRoute、NavigationEndをインポートしてください。そうすればすべてうまくいくはずです。
ちょっと遅く答えて申し訳ありません。 Angularルーティングドキュメントには、ページアンカーへのハッシュタグを使ったルーティングを手助けするための定義済み関数があります。つまり、anchorScrolling: 'enabled'
Step-1: -まずapp.module.tsファイルにRouterModuleをインポートしてください: -
imports:[
BrowserModule,
FormsModule,
RouterModule.forRoot(routes,{
anchorScrolling: 'enabled'
})
],
Step-2: - HTMLページに行き、ナビゲーションを作成し、それぞれにマッチさせるために[routerLink]とfragmentのような二つの重要な属性を追加します部署ID: -
<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>
Step-3: -ID nameとfragmentを一致させることでセクション/ 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>
あなたの参考のために、私はあなたの問題を解決するのに役立つ小さなデモを作成することによって以下の例を加えました。
前の答えのどれも私のために働きませんでした。最後の努力として、私は自分のテンプレートを試してみました。
<a (click)="onClick()">From Here</a>
<div id='foobar'>To Here</div>
私の.tsでこれで:
onClick(){
let x = document.querySelector("#foobar");
if (x){
x.scrollIntoView();
}
}
そしてそれは内部リンクのために期待通りにはたらきます。これは実際にはアンカータグを使用しないので、URLにはまったく触れません。
上記の解決策は私のために動作しませんでした...これはそれをやった:
まず、自動スクロール用のMyAppComponent
を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 );
}
}
} );
}
}
}
それから、prodID
ハッシュタグを送信するmy-app-route
に移動します。
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">
他のすべての答えはAngular version <6.1で機能します。しかし、あなたが最新版を手に入れたならば、Angularが問題を解決したので、あなたはこれらの醜いハックをする必要はないでしょう。
あなたがする必要があるのはscrollOffset
をRouterModule.forRoot
メソッドの2番目の引数のオプションで設定することだけです。
@NgModule({
imports: [
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled',
anchorScrolling: 'enabled',
scrollOffset: [0, 64] // [x, y]
})
],
exports: [RouterModule]
})
export class AppRoutingModule {}
Kalyoyanの answer に加えて、この購読はルーターに結び付けられており、ページが完全に更新されるまで存続します。コンポーネント内のルータイベントを購読するときは、必ず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();
}
}
私はこれを自分のウェブサイト上で動作させたところなので、ここに私の解決策を掲載する価値があると考えました。
<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 {
}
それは私にとって本当にうまくいった。
Fragmentプロパティはまだアンカースクロールを提供していないので、この回避策は私にとってはトリックでした。
<div [routerLink]="['somepath']" fragment="Test">
<a href="#Test">Jump to 'Test' anchor </a>
</div>
クエリパラメータを指定せずにページに対して機能する簡単な解決策は、ブラウザのバック/フォワード、ルーター、およびディープリンク準拠です。
<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によって "保護された"動的データをページにロードさせることです。これは、ルートを変更するときにページの一番上までスクロールするためにも使用できます。デフォルトの一番上のアンカータグを指定するだけです。
JavierFuentesの回答を参照する別の回避策を次に示します。
<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
でルートフラグメントをサブスクライブしましたが、ngDoCheck
ごとにngAfterViewChecked()
が連続して呼び出され、ユーザーがトップに戻ることができないため、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);
}
これは私のために働く!このngForは動的にタグを固定するので、それらをレンダリングするのを待つ必要があります
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>
私のtsファイル:
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
を追加することを忘れないでください。
私は同じ問題を抱えていました。解決策:ビューポートスクローラーを使用する https://angular.io/api/common/ViewportScroller#scrolltoanchor
- app-routing.module.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);
}
}
他の答えとは異なり、私はさらにfocus()
と共にscrollIntoView()
を追加します。また、URLを変更するとsetTimeout
を使用します。その理由が何であるかは定かではありませんが、setTimeout
が回避策を実行するようです。
原点:
<a [routerLink] fragment="some-id" (click)="scrollIntoView('some-id')">Jump</a>
先:
<a id="some-id" tabindex="-1"></a>
TypeScript:
scrollIntoView(anchorHash) {
setTimeout(() => {
const anchor = document.getElementById(anchorHash);
if (anchor) {
anchor.focus();
anchor.scrollIntoView();
}
});
}
私はこれらの解決策のほとんどを試したが、うまくいかない別のフラグメントを残して戻ってくる問題に遭遇したので、私は100%うまくいく少し違う何かをし、そしてURLの醜いハッシュを取り除いた。
tl; drこれが私が今まで見たことよりも良い方法です。
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();
}
}
私はnmp - ngx-scroll-to で利用可能な非常に便利なプラグインをテストしたところです。ただし、Angular 4+用に設計されていますが、この回答が役に立つことがあるかもしれません。