Angular4 - прокрутка к якорю
Я пытаюсь сделать простую прокрутку к элементу привязки на той же странице. В принципе, человек нажимает кнопку "Попробовать", и он прокручивается до области ниже на странице с идентификатором "login". Сейчас он работает с базовыми id="login"
и <a href="#login"></a>
, но он переходит в этот раздел. В идеале, мне бы хотелось, чтобы он прокручивался туда. Если я использую Angular4, есть ли встроенный способ сделать это или что является самым простым способом? Спасибо!
Целый шаблон... (компонент все еще пуст)
<div id="image-header">
<div id="intro">
<h1 class="text-center">Welcome to ThinkPlan</h1>
<h3 class="text-center">Planning your way</h3>
<a class="btn btn-outline-primary" href="#login" id="view">Try It</a> <!-- Where the user clicks to scroll -->
</div>
</div>
<div class="container" id="info">
<div class="row">
<div class="col-md-12">
<div class="space" id="login"></div> <!-- The place to scroll to -->
<h1 class="text-center">ThinkPlan</h1>
<form class="form-horizontal">
<fieldset>
<legend>Login</legend>
<div class="form-group">
<label for="inputEmail" class="col-lg-2 control-label">Email</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="inputEmail" placeholder="Email">
</div>
</div>
<div class="form-group">
<label for="inputPassword" class="col-lg-2 control-label">Password</label>
<div class="col-lg-10">
<input type="password" class="form-control" id="inputPassword" placeholder="Password">
</div>
</div>
<div class="form-group" id="log-btn">
<div class="col-lg-10 col-lg-offset-2">
<button routerLink="/plan" type="submit" class="btn btn-outline-primary">Login</button>
</div>
</div>
<p class="lead text-center">New here? <a routerLink="signup">Sign up.</a></p>
</fieldset>
</form>
</div>
</div>
</div>
Ответы
Ответ 1
Я думаю, что это более простое решение:
В вашем HTML:
<a [routerLink]="['/']" fragment="login"></a>
В typescript:
ngOnInit() {
this.route.fragment.subscribe(fragment => { this.fragment = fragment; });
}
ngAfterViewChecked(): void {
try {
if(this.fragment) {
document.querySelector('#' + this.fragment).scrollIntoView();
}
} catch (e) { }
}
Ответ 2
Автоматическая прокрутка
Начиная с Angular v6, появилась новая опция anchorScrolling
для RouterModule
. Вы можете установить его в модуле импорта:
imports: [
...,
RouterModule.forRoot(routes, {anchorScrolling: 'enabled'})
При этом Angular автоматически прокрутит до элемента с идентификатором данного фрагмента.
⚠️ Однако, это не работает, когда данные загружаются асинхронно, см. эту проблему Github. ⚠️
Ручная прокрутка
С помощью RouterModule
плавная прокрутка пока невозможна, но вы можете сделать это вручную:
1) Получите вашу цель, например с ViewChild
:
@ViewChild('pageInfo') pageInfo: ElementRef;
2) Позвоните scrollIntoView
на nativeElement
:
const targetElement = this.pageInfo.nativeElement
targetElement.scrollIntoView({behavior: "smooth"})
Ответ 3
С Angular 4 у вас может возникнуть проблема с привязкой к той же странице.
Я решил использовать этот способ
ng2-page-scroll
установить
npm install ng2-page-scroll --save
импортировать в ваш app.module.ts
import {Ng2PageScrollModule} from 'ng2-page-scroll';
@NgModule({
imports: [
/* Other imports here */
Ng2PageScrollModule
]
})
export class AppModule {
}
проверить его в компоненте html
<a pageScroll href="#test">Testing</a>
<div id="test">
Ответ 4
AfterViewCheck()
будет вызываться каждый раз при срабатывании ChangeDetection
, поэтому это плохое решение.
Использовать AfterViewInit()
как
public ngAfterViewInit(): void {
this.subscription = this.route.fragment
.subscribe(fragment => {
const targetElement = this.document.querySelector('#' + fragment);
if (fragment && targetElement) {
targetElement.scrollIntoView();
} else {
window.scrollTo(0, 0);
}
});
}
public ngOnDestroy(): void {
this.subscription.unsubscribe();
}
Ответ 5
Это более подробный пример, который можно добавить к ответу Сары Дюбуа выше.
Импорт модулей маршрутизатора.
import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';
constructor(private route:ActivatedRoute,
private router:Router) {
router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
if (event.url) {
this.route.fragment.subscribe(fragment => this.fragment = fragment);
}
}
});
}
ngAfterViewChecked(): void {
try {
if(this.fragment != null) {
document.querySelector("a[name="+this.fragment+"]").scrollIntoView();
}
} catch (e) {
//console.log(e, 'error');
}
}
Мне нравится использование querySelector, которое даст вам много опций, к какому элементу вы хотите перейти. https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
Это работает с Angular 8 :)