【问题标题】:ngAfterViewInit is not working or am I doing something wrongngAfterViewInit 不工作或者我做错了什么
【发布时间】:2019-12-17 22:22:15
【问题描述】:

我的 ngAfterViewInit 函数没有按预期工作。我觉得我在这里遗漏了一些东西。

  ngOnInit() {
   this.dataService.getUsers().subscribe((users) => {this.users = users) ;  
  }

  ngAfterViewInit() {
    if (document.getElementById('target')) {
        document.getElementById('target').scrollIntoView({
          behavior: 'auto',
          block: 'center',
          inline: 'center',
       });
   }

所以基本上,在视图完成加载后,我使用ngAfterViewInint() 函数滚动到当前项目。在ngOnInit() 内部,如果我不调用subscribe() 并在其中放置一个变量。它工作得很好。但事实并非如此。

我可以在ngAfterViewInit() 中使用setTimeOut()。但我不喜欢它。我不喜欢它依赖超时的事实。而且我认为会有更好的解决方案。 有什么理想吗?谢谢大家。

【问题讨论】:

  • 您的target 元素是否依赖于从您的请求返回的数据?
  • 您不能在 Angular 2+ 中引用这样的元素 调用子原生元素时请参阅此内容 stackoverflow.com/questions/48226868/…
  • @Pyth 是的。是的。
  • @Rager 谢谢。让我试试。
  • ????我认为@ViewChildren 是她的完美方式,我已经包含了我的答案希望它有帮助????

标签: javascript angular typescript


【解决方案1】:

更好的解决方案是使用 ViewChildren 装饰器,因为您可以订阅视图的更改,这意味着您不需要使用 setTimeOut

  @ViewChildren("target") target: QueryList<ElementRef>;

  ngOnInit() {
   this.dataService.getUsers().subscribe((users) => {this.users = users) ;  
  }

  ngAfterViewInit() {
    this.target.changes.subscribe(({ first: elm }) => {

      elm.nativeElement.scrollIntoView({
        behavior: "auto",
        block: "center",
        inline: "center"
      });

    });
  }

stackblitz demo ?

【讨论】:

    【解决方案2】:

    看起来您的代码取决于在调用 ngAfterViewInit() 之前返回的 dataService.getUsers() 调用?

    如果是这样,那是行不通的,因为无法保证时间。 而是这样做:

     ngAfterViewInit() {
       this.dataService.getUsers().subscribe((users) => {
          this.users = users;
          this.scrollTargetIntoView();
       )};
     }
    
      scrollTargetIntoView() {
        if (document.getElementById('target')) {
            document.getElementById('target').scrollIntoView({
              behavior: 'auto',
              block: 'center',
              inline: 'center',
           });
       }
    

    即使这可能有点太早了——你可能想给它添加一个 setTimeout() 来给 DOM 一个渲染的机会,例如:

    ngAfterViewInit() {
       this.dataService.getUsers().subscribe((users) => {
          this.users = users;
          setTimeout(() => this.scrollTargetIntoView());
       )};
     }
    
      scrollTargetIntoView() {
        if (document.getElementById('target')) {
            document.getElementById('target').scrollIntoView({
              behavior: 'auto',
              block: 'center',
              inline: 'center',
           });
       }
    

    【讨论】:

      【解决方案3】:

      如果您的 Angular 应用程序有路由,那么您可以查看的另一个选项是 Route Resolvers,它可以在导航到特定路由之前为组件预取数据。这样,您的 UI 将拥有在 ngOnInit() 生命周期挂钩中呈现所需的所有必要数据。

      您可以使用以下代码创建解析器服务:

      @Injectable()
      export class UserResolverService implements Resolve<Observable<User[]>> {
        constructor(private dataService: DataService) {}
      
        resolve() {
          return this.dataService.getUsers()
        }
      }
      

      然后在您的路由定义中,您可以使用以下方法激活解析器:

      const routes: Routes = [
        {
          path: 'my_path',
          component: MyComponent,
          resolve: {
            users: UserResolverService
          }
        }
      ];
      

      最后,在您的组件 ngOnInit() 生命周期挂钩中,您可以使用以下代码使用数据:

      constructor(private route: ActivatedRoute) {}
      
      ngOnInit() {
        this.users = this.route.snapshot.data.users;
      }
      
      ngAfterViewInit() {
        if (document.getElementById('target')) {
          document.getElementById('target').scrollIntoView({
            behavior: 'auto',
            block: 'center',
            inline: 'center',
          });
        }
      }
      

      【讨论】:

        猜你喜欢
        • 2021-04-17
        • 2021-08-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-25
        • 1970-01-01
        相关资源
        最近更新 更多