我的应用程序有两个父组件A和B,每个组件都在各自的模块中(分别为模块A和B)。组件A包括其自身模块(模块C)中的子组件C。组件B包括子组件C(来自模块C)和子组件B1来自模块B。各个父/子组件之间的所有交互和行为都正常。我遇到的问题是尝试使组件(B1)将元素(elemOfInterest)滚动到视口顶部,以响应组件C通过数据共享服务发出的标志(flagA)。
当我从组件A的模板单击子组件C的表单提交按钮时,我被路由到组件B。但是,如果没有setTimeout,子组件B1中的scrollToView将无法工作。触发组件B1的ngOnInit生命周期后,单击组件C的表单提交按钮(这次是从组件B的模板),这会使scrollToView方法在没有setTimeout的情况下也可以正常工作。我一生都无法弄清ngOnInit为什么会干扰组件B1中的scrollToView。这是我的代码:
ComponentC.component.ts:
export class ComponentC implements OnInit {
constructor(private dataSharing: DataSharingService) {}
ngOnInit() {
doSomething(){
this.dataSharing.transferData({'data':{'flagA':true}});
}
}
}
ComponentC.component.html:
<form class="mx-auto" [formGroup]="searchForm" (ngSubmit)="doSomething()">
<div> … </div>
<div> <button type="submit">Submit</button> </div>
</form>
ComponentB1.component.ts
export class ComponentB1 implements OnDestroy, OnInit {
subscriptions: Subscription = new Subscription();
constructor(private dataSharing: DataSharingService) {}
ngOnInit() {
this.subscriptions.add(
this.dataSharing.outgoingData$.subscribe(data => {
this.onSharedData(data);
})
)
}
onSharedData(data) {
if (Object.keys(data).length && Object.keys(data['data']).length) {
switch (true) {
case data['data']['flagA']:
this.func1();
break;
case data['data']['flagB']:
this.func2();
break;
}
}
}
ngOnDestroy() {this.subscriptions.unsubscribe()}
func1(){
//do something simple, like set html element values, etc.
setTimeout(()=>document.getElementById('elemOfInterest').scrollIntoView({behavior: 'smooth', block: 'start', inline: 'nearest'}));
}
}
数据共享服务代码:
import { Injectable } from '@angular/core';
import { Observable, ReplaySubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class DataSharingService {
outgoingData$ = new ReplaySubject(1);
constructor() {}
transferData(incomingData: object){
this.outgoingData$.next(incomingData);
}
}
对于它的价值,我也尝试过使用jQuery
$('html, body').animate({ scrollTop: $('#elemOfInterest).offset().top }, 'slow')
代替scrollToView,但在首次启动组件B1时仍需要setTimeout才能使滚动正常工作。知道如何在不使用setTimeout的情况下完成滚动行为吗?
答案 0 :(得分:0)
outgoingData$
是一个ReplaySubject,这意味着它将立即向每个新订户发出最后一个值。因此,如果应用早些时候调用了transferData
,则此重放主题已经具有一定的价值(请注意,DataSharingService
是代码段中应用范围内的单例对象,导航时不会重新创建它)
现在ComponentB1在ngOnInit中订阅了它。订阅后,重放主题立即发出-就在此ngOnInit执行期间。此时ComponentB1尚未由Angular渲染-因此elemOfInterest
可能尚不存在。