在每个组件完成加载后如何在 Angular 2 中运行 jquery 函数

Posted

技术标签:

【中文标题】在每个组件完成加载后如何在 Angular 2 中运行 jquery 函数【英文标题】:How to run a jquery function in Angular 2 after every component finish loading 【发布时间】:2016-06-14 05:08:56 【问题描述】:

我已经尝试了所有生命周期钩子,但无法完成所需的结果。 我需要的结果是触发一个函数,该函数在加载每个元素(组件)后初始化用于单个页面上不同元素的许多 jquery 插件。

假设你有这个结构。

主页 滑块 小部件 产品旋转器 ..等等

这些元素中的每一个都有自己的组件,并且都是主页父组件的子组件。

这里我需要知道所有子组件和父组件何时加载,因此我触发了一个 jquery 函数来初始化页面上的每个插件。

【问题讨论】:

你找到解决这个问题的办法了吗? 【参考方案1】:

您将希望通过导入 AfterViewInit (https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#afterview) 来使用“ngAfterViewInit”生命周期挂钩。可以如下图使用:

安装:

    tsd install jquery --save

    typings install dt~jquery --global --save

利用:

    import  Component, AfterViewInit  from '@angular/core';
    import * as $ from 'jquery';

    ngAfterViewInit() 
        this.doJqueryLoad();     
        this.doClassicLoad();

        $(this.el.nativeElement)
            .chosen()
            .on('change', (e, args) => 
                this.selectedValue = args.selected;
            );
    

    doClassicLoad() 
      // A $( document ).ready() block.
      $( document ).ready(function() 
          console.log( "Unnecessary..." );
      );      
    

    // You don't need to use document.ready... 
    doJqueryLoad() 
        console.log("Can use jquery without doing document.ready")
        var testDivCount = $('#testDiv').length;
        console.log("TestDivCount: ", testDivCount);
    

这是一个例子: http://plnkr.co/edit/KweZYO9hk9Dz8pqDK77F?p=info

【讨论】:

错误:Cannot find name '$' Angular 2 Final 看来您现在必须声明美元符号。 我在使用 ngAfterViewInit 和 jquery 时遇到问题,因为当我尝试定位元素时它们不存在:ngAfterViewInit() console.log($('#startDateTimeFilter, #endDateTimeFilter).length ); 显示 0 而不是 2。 您的代码中是否有一个尾随撇号,这里缺少一个撇号。我创建了一个获取 div 长度并返回 1 的 plunker。请参见此处:plnkr.co/edit/KweZYO9hk9Dz8pqDK77F 如果你有依赖于 Jquery 的依赖,你应该把 "scripts": [ "node_modules/jquery/dist/jquery.js", 放到你的 angular.json 文件中以获得 angular 6+【参考方案2】:

我发现最有效的方法是在页面/组件构造函数中使用时间为 0 的 setTimeout。这让 jQuery 在 Angular 加载完所有子组件后的下一个执行周期中运行。

export class HomePage 
    constructor() 
        setTimeout(() => 
            // run jQuery stuff here
        , 0);
    

将 setTimeout 放在 ngOnInit 方法中也对我有用。

export class HomePage 
    ngOnInit() 
        setTimeout(() => 
            // run jQuery stuff here
        , 0);
    

【讨论】:

这对我有用,但感觉很hacky!是否有关于“正确”方法的更新? Timeout = 0 对我不起作用,但 timeout = 1 起作用。 我使用的不是 JQuery,而是 document.querySelector()。在我遇到这个之前,我已经旋转了几个小时。谢谢! 感谢您的提示。它对我有用...看来我们应该能够在没有这种 hack 的情况下在“AfterViewInit”函数中访问 dom。【参考方案3】:

怎么样

bootstrap(...).then(x => 
  ...
)

否则我会假设你的根组件的ngAfterViewInit() 是一个符合你要求的生命周期钩子,但你说你已经测试了所有......

更新

根组件上的bootstrap()ngAfterViewInit() 只能用于初始加载。对于以后添加的组件,可以使用添加的组件的ngAfterViewInit()

【讨论】:

我试过了,但是这些事件在页面上没有任何内容之前触发,例如我试图触发他们两个的警报,我得到了这个结果。 postimg.org/image/8qv5tqei9 如您所见,页面上还没有任何内容。我想在页面上的所有内容完全加载后初始化 jquery 插件。生活的钩子似乎都不起作用。 我还没有检查 bootstrap.then 但对于 ngAfterViewInit 来说这不是真的 对我也不起作用。既不是 bootstrap(...).then() 想法,也不是根组件的 ngAfterViewInit() 钩子。对我有用的是在每条路由的每个叶子组件的 ngAfterViewInit 中添加 jquery 插件初始化。【参考方案4】:

我在这里遇到了同样的问题。我找到了 2 个解决方案,即使它们不是最好的:

1 - 实现 afterViewChecked 以检查 jquery 插件是否已启动,然后使用变量来控制其初始化。这是困难的方式,因为 afterViewChecked 被调用了很多次。

2 - 我使用 hidden 属性而不是 ngIf 将一些元素更改为隐藏。使用 hidden 我可以使用 afterViewInit 初始化所有 jquery 插件,即使我的对象被隐藏,它们也可以工作。

使用 ngIf 时 setTimeout 不起作用。它在重新渲染内容之前触发。

【讨论】:

【参考方案5】:

一种可能的解决方案是订阅zone.onStablezone.onMicrotaskEmpty

ngAfterViewInit() 
  this.zone.onStable.first().subscribe(() => 
    debugger;
  );

ngOnInit() 
  this.service.getData().subscribe(() => 
    this.data = data;
    this.zone.onMicrotaskEmpty.first().subscribe((data) => 
      $(someElem).plugin();
    );
  );

另见

Angular 2 calling jQuery after rendering elements - after consuming API

【讨论】:

以上是关于在每个组件完成加载后如何在 Angular 2 中运行 jquery 函数的主要内容,如果未能解决你的问题,请参考以下文章

Angular 5 - 动态组件模板加载

Angular 5 - 如何在初始化后重新加载组件

Angular 2/4:为每个模块加载 sass 变量

Angular 2在组件加载时将焦点放在表单的第一个字段上

如何在 Angular 2 中重新加载相同 URL 的组件?

如何检查数据是不是已完成加载以使用异步管道 Angular 8