0

我正在将 Angular 10 用于我的一个副项目。我有一个页面,在页面加载时,它从服务器检索条目列表(在这种情况下特别是),并在该页面上为每个条目spells呈现 1 个子组件(组件)。<app-spell>用户可以(这是可选的)指定一个名为的 url 参数name,如果他这样做并且有一个条目为真,spell.name === name那么我想滚动到该条目的组件。

我被困在试图获得这些孩子名单的地方。Ì 计划ViewChildren用于获取子组件列表。但是,似乎没有任何适当的生命周期钩子具有准确的值。此外,即使尝试使用 document.querySelector(我提前知道我将拥有一个 id 为“Arawns-Changing-Scales”的组件),我似乎也无法获得所需的 HTML 元素:

  1. ngAfterContentInit: 你ViewChildren一般不能在这个钩子里访问。document.querySelector-调用返回空值。
  2. ngAfterViewInit:此时尚未获取条目,也没有初始化子组件。因此ViewChildren返回一个空的QueryList. document.querySelector` 返回 null
  3. ngOnInit: 子组件尚未初始化。因此ViewChildren返回一个空的QueryList. document.querySelector返回空

在那之后,我没有合适的看似生命周期的钩子。我已经尝试了这里的建议并将我的访问尝试ViewChildren放入 setTimeout 回调中,这只是返回与根本不使用超时相同。我发现的其他问题是使用点击或其他用户触发的事件来触发滚动,这对我来说不是这样。

在页面加载过程中,我在哪里可以获得某种 HTMLElements/Components?

## spells.component.html

        <!-- Spells -->
        <div *ngFor="let spell of spells; let i = index">
            <app-spell
            #spellElements
            [id]="spell.name.replaceAll(' ', '-').replace('\'', '')"
            [index] = "i"
            [cardData] = "spell"
            *ngIf="hasSelectedClasses(spell)"
            ></app-spell>
        </div>
## spells.component.ts

@Component({
  selector: 'app-spells',
  templateUrl: './spells.component.html',
  styleUrls: ['./spells.component.scss']
})
export class SpellsComponent implements OnInit, AfterContentInit, AfterViewInit {
  panelIsOpenArray: boolean[];
  spells: SpellObject[];

  @ViewChildren("spellElements") spellElements: QueryList<any>;

  constructor(
    private spellService: SpellService,
    public routingService: RoutingService,
    private route: ActivatedRoute,
  ) { }

  ngOnInit(): void {
    this.spellService.list().pipe(first()).subscribe(
      (spells: SpellObject[]) => {
        this.spells = spells;
        this.panelIsOpenArray = [];
        for (let spell of spells){
          this.panelIsOpenArray.push(true);
        };

        console.log("After init");
        this.scrollToSpellInUrl();
      },
      error => this.routingService.routeToErrorPage(error)
    );
  }
  ngAfterViewInit(): void{
    setTimeout(_=> {
      console.log("After view init in timeout");
      this.scrollToSpellInUrl()
    });

    console.log("After view init normal")
    this.scrollToSpellInUrl();
  }

  ngAfterContentInit(): void{
    console.log("After content init");
    this.scrollToSpellInUrl();
  }

  scrollToSpellInUrl(){
    console.log(this.spellElements);
    console.log(document.getElementById("Arawns-Changing-Scales");
    console.log(document.querySelector("#Arawns-Changing-Scales"));
    return;
  }

  hasSelectedClasses(spell: SpellObject): boolean{
    //For all intents and purposes, based on some other data and this
    //data this function returns sometimes true sometimes false, more 
    //is not relevant for this question.
  }
}
4

1 回答 1

2

您可以使用ViewChildren注释来监视 SpellComponents。注释公开了一个QueryList,它首先填充在 ngAfterViewInit 钩子中。在您的情况下,您正在以异步方式获取咒语,并且您无法及时获取 ngAfterViewInit 钩子。然而 Querylist 有一个changes属性,它是一个 Observable,它会在任何时候从模板中添加、删除或移动 SpellComponent 时发出。

  @ViewChildren(SpellComponent)
  public spellsComponents: QueryList<SpellComponent>;

  public ngAfterViewInit() {
    this.spellsComponents.changes.subscribe(queryList => {});
  }

在每次发出时,我们可以在 queryList 参数中进行搜索。但在此之前是我的 SpellComponent:

export class SpellComponent implements OnInit {
  @Input() name: string;

  constructor(public element: ElementRef) {}

  ngOnInit() {}
}

我们将使用名称 Input 来识别我们的拼写组件。我注入ElementRef因为它可以让我们使用element.scrollIntoView方法。

this.spellsComponents.changes.subscribe(queryList => {
  const target = queryList.find(cmp => cmp.name === "foo");
  target.element.nativeElement.scrollIntoView();
});

完毕。这是一个现场演示https://stackblitz.com/edit/angular-mmjzwj-jffmyr?file=app.module.ts

于 2021-08-02T19:44:32.827 回答