Angular4 - 滚动到锚点
Posted
技术标签:
【中文标题】Angular4 - 滚动到锚点【英文标题】:Angular4 - Scrolling to anchor 【发布时间】:2017-11-10 11:39:22 【问题描述】:我正在尝试对同一页面上的锚元素进行简单的滚动。基本上,该人单击“尝试”按钮,然后滚动到页面下方的区域,ID 为“登录”。现在,它正在使用基本的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】:对于 Angular 6+,您可以使用:
在你的路由模块中:
imports: [RouterModule.forRoot(routes, anchorScrolling: 'enabled')]
然后在你的组件html中
<a (click)="onClick('AnchorId')">Click me!</a>
<a (click)="onClick('OtherAnchorId')">Click me, too!</a>
...
<div id="AnchorId">...</div>
...
<div id="OtherAnchorId">...</div>
然后在你的组件中 ts
import ViewportScroller from '@angular/common';
@Component(
selector: 'component-selector',
templateUrl: './mycomponent.component.html'
)
export class MyComponent
constructor(private viewportScroller: ViewportScroller)
public onClick(elementId: string): void
this.viewportScroller.scrollToAnchor(elementId);
【讨论】:
不错,但您不需要导入:[RouterModule.forRoot(routes, anchorScrolling: 'enabled')] viewportScroller 不需要路由器模块作为依赖项 即使 Kim Kern 的回答是正确的,这感觉更像是“Angular 框架”。您还可以添加 css: "html scroll-behavior: smooth;" 使其更愉快。 完美,但是滚动事件呢? 这对于页面部分滚动很有用。要在新选项卡中打开 URL 并重定向到特定部分,请检查 @Sarah Dubois 答案。【参考方案2】:我认为这是更简单的解决方案:
在您的 HTML 中:
<a [routerLink]="['/']" fragment="login"></a>
在你的打字稿中:
ngOnInit()
this.route.fragment.subscribe(fragment => this.fragment = fragment; );
ngAfterViewChecked(): void
try
if(this.fragment)
document.querySelector('#' + this.fragment).scrollIntoView();
catch (e)
【讨论】:
这会重定向到根路由。要在同一页面位置添加哈希,使用<a routerLink="." fragment="login"></a>
效果更好。
这种方法比 'npm install ng2-page-scroll' 更好。但它在没有平滑滚动的情况下工作
你可以像这样平滑滚动:scrollIntoView(behavior: "smooth")
呃,this.route
是什么??
@SarahDubois 这是一个非常棒的解决方案,对我使用 Angular 版本 8 非常有用。五颗星因为它的简单性。 @Phil this.route
是ActivatedRoute。您可能需要这些导入 import ActivatedRoute, Router, NavigationEnd from '@angular/router';
我可以发布更多详细信息的答案。【参考方案3】:
自动滚动
从 Angular v6 开始,RouterModule
有了新的 anchorScrolling
选项。您可以在模块的导入中设置它:
imports: [
...,
RouterModule.forRoot(routes, anchorScrolling: 'enabled')
这样,Angular 将自动滚动到具有给定片段 id 的元素。
⚠️ 但是,这在异步加载数据时不起作用,请参阅此Github issue。 ⚠️
手动滚动
Smooth scrolling 尚无法通过RouterModule
实现,但您可以手动完成:
1) 获取目标,例如ViewChild
:
@ViewChild('pageInfo') pageInfo: ElementRef;
2) 在nativeElement
上致电scrollIntoView
:
const targetElement = this.pageInfo.nativeElement
targetElement.scrollIntoView(behavior: "smooth")
【讨论】:
这是正确的。谢谢。要为其他人添加此内容,请使用 ViewChild 获取目标参考; @ViewChild('pageInfo') elemPageInfo: ElementRef; this.elemPageInfo.nativeElement.scrollIntoView(behavior: 'smooth'); @Ralphonzo 很高兴听到。 :-) 感谢您的精彩补充,我已经编辑了答案。 请详细说明选项2中的“targetElement”是什么。它是可滚动元素? @ShacharHar-ShuvtargetElement
是您要滚动到的元素,以便它在浏览器的视口中可见。
链接到关于anchorScrolling的Angular文档here【参考方案4】:
现代单线解决方案:
export class Component implements AfterViewInit
constructor(
private viewportScroller: ViewportScroller
)
ngAfterViewInit(): void
this.route.fragment.pipe(
first()
).subscribe(fragment => this.viewportScroller.scrollToAnchor(fragment));
【讨论】:
【参考方案5】:所以,我只花了大约一个小时使用最新的 Angular 和其他解决方案进行初始导航,但无论我尝试什么,我都无法让锚滚动与导航历史记录一起使用。
换句话说,当我在浏览器中“返回”或“前进”时,URL 会更新,但我无法让 Angular 滚动到正确的位置。从记录来看,Angular 在后退/前进时似乎实际上并没有确认片段,因此没有触发滚动。
我受够了,决定订阅 URL 并在找到片段时手动滚动,代码如下:
ngOnInit()
this.router.events.subscribe(val =>
if (val instanceof NavigationEnd)
let fragmentIdx = val.urlAfterRedirects.lastIndexOf('#');
if (fragmentIdx >= 0 && fragmentIdx < val.urlAfterRedirects.length - 1)
let fragment = val.urlAfterRedirects.substring(fragmentIdx+1);
console.log('fragment: ' + fragment);
document.getElementById(fragment).scrollIntoView();
)
为了清楚起见,您必须为要滚动到的目标元素指定 id
。
另外,我的链接如下所示:
<a routerLink="." fragment="anchor-name">Scroll To Anchor</a>
现在,我可以访问不同的锚点,并在我回溯/前进历史时查看滚动。希望它可以帮助某人!
【讨论】:
【参考方案6】:在 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">
【讨论】:
感谢您的全面回答,我试过了,但 npm 模块的对等依赖项已过时,具有最新的 Angular 版本。 它不起作用。在角度为 6 的列表中。单击后我的页面正在重新加载【参考方案7】: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();
【讨论】:
为什么我们需要在 ngOnDestroy 中手动取消订阅?我认为 Angular 会自动执行它,因为它是一个路由订阅。【参考方案8】:最后,在 Angular 7 中为我工作:
HTML:
<h1 id='here'>Here</h1>
组件:
ngAfterViewInit()
this.route.fragment.subscribe(fragment =>
this.fragment = fragment;
setTimeout(() => this.scrollToAnchor(), 10);
);
scrollToAnchor(): void
try
if (this.fragment)
document.querySelector('#' + this.fragment).scrollIntoView();
catch (e)
goToHere():void
this.router.navigate(['/product'], fragment: 'here' );
【讨论】:
【参考方案9】:这是一个更详细的示例,可以添加到上述 Sarah Dubois 的答案中。
导入路由器模块。
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 :)
【讨论】:
以上是关于Angular4 - 滚动到锚点的主要内容,如果未能解决你的问题,请参考以下文章