如何使ScrollIntoView起作用而不必使用setTimeout

问题描述 投票:0回答:1

我的应用程序有两个父组件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的情况下完成滚动行为吗?

javascript scroll angular7 settimeout
1个回答
0
投票

outgoingData$是ReplaySubject,这意味着它将立即向每个新订户发出最后一个值。因此,如果应用程序较早调用了transferData,则此重放主题已经具有一定的价值(请注意,DataSharingService是代码段中应用程序范围内的单例,在导航时不会重新创建它。)>

现在ComponentB1在ngOnInit中订阅它。订阅后,重放主题立即发出-就在此ngOnInit执行期间。此时ComponentB1尚未由Angular渲染-因此elemOfInterest可能尚不存在。

© www.soinside.com 2019 - 2024. All rights reserved.