尝试 link 当前页面中的某个部分时出现无效选择器错误

Not a valid selector error when trying to link to a section within the current page

我正在制作一个常见问题解答页面,所有问题都以超链接形式显示在顶部。当您单击超链接时,您将被定向到页面上可以阅读问题答案的部分。为此,我正在尝试使用 Kaloyan 提供的 Angular2 Routing with Hashtag to page anchor 此处提供的解决方案。 该解决方案在代码行

对我来说中断了
  const element = document.querySelector("#" + tree.fragment);

这给出了错误 ERROR DOMException: Failed to execute 'querySelector' on 'Document': '#1' is not a valid selector.。我能理解为什么会出现此错误,因为它正在寻找选择器,并且它获得的输入是#fragment。然而,我提到的 Whosebug 线程中的每个人都说它有效,所以也许我做错了什么。当我用 getElementById(tree.fragment) 替换 querySelector 时,我不再收到错误,但是当我单击其中一个链接时,页面也不会跳转到该部分。有人可以告诉我我做错了什么部分或者我错过了在提到的线程中从解决方案中实现的哪一部分吗?谢谢。

这是我的代码:

组件代码:

import { Component, OnInit } from '@angular/core';
import { FaqItem } from './faq-item.model';
import { Router, NavigationEnd } from '@angular/router';

@Component({
  selector: 'app-faq',
  templateUrl: './faq.component.html',
  styleUrls: ['./faq.component.css']
})
export class FaqComponent implements OnInit {

  faqItems: FaqItem[] = EXAMPLE_DATA;



  constructor(router: Router) {

    router.events.subscribe(s => {
      if (s instanceof NavigationEnd) {
        const tree = router.parseUrl(router.url);
        if (tree.fragment) {
          const element = document.querySelector("#" + tree.fragment);
          // const element = document.getElementById(tree.fragment);
          if (element) { element.scrollIntoView(true); }
        }
      }
    });

  }

  ngOnInit() {
  }

}

const EXAMPLE_DATA: FaqItem[] = [
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},

    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},  {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},
    {id: 1, question: 'How do i use the seedcalendar app?', answer: 'please check the getting started tutorial for this'},

]
export class FaqItem {
    id: number;
    question: string;
    answer: string;
}

HTML代码:

<section id="top">
  <ol>
    <li *ngFor="let item of faqItems; let i=index">
        <a [routerLink]="['.']" fragment={{i}}>{{item.question}}</a>
    </li>
  </ol>
<dl>
  <app-faq-item *ngFor="let item of faqItems; let i=index" 
  [question]="item.question" [answer]="item.answer" [attr.id]="i">
</app-faq-item>
</dl>
</section>

我理解使用 fragment 作为锚点 links 的方式(我可能是错的)是在路线之间导航时使用它们,并且您希望将用户带到某个点导航到该页面后的页面。

您的问题似乎表明您更愿意单击页面上的 link 并将用户滚动到相应的部分。

如果这是准确的,您可以使用 @ViewChildren:


添加模板引用(#answers):

<app-faq-item #answers *ngFor="let item of faqItems; let i=index" [...] [...]>

以及问题的点击处理程序:

<a href="javascript:;" (click)="scrollTo(i)">{{item.question}}</a>

并在您的组件中,使用 ViewChildren 获取当前元素:

export class FaqComponent implements OnInit {

  faqItems: FaqItem[] = EXAMPLE_DATA;
  @ViewChildren('answers', { read: ViewContainerRef }) answers;

  scrollTo(index: number) {
    const element = this.answers.toArray()[index].element.nativeElement;
    element.scrollIntoView({
      behavior:"smooth",
      block: "start", 
      inline: "nearest"
    });
  }

这里是Demo.