在Angular2中,当视图发生变化时,视图不会自动更新。

17 浏览
0 Comments

在Angular2中,当视图发生变化时,视图不会自动更新。

我开始探索Angular2(我之前有Angular1和一点React的背景),但是我在一个问题上卡住了。我想要将特定的按键绑定到我的组件中的动作,所以我决定使用Angular2的生命周期来绑定/解绑动作。然而,如果我在Mousetrap回调函数中做一些操作,它是有效的,但是直到运行一个脏检查周期之后,它才会被渲染和显示出来。我需要显式地运行一些东西来更新视图吗?有人可以帮助我弄清楚发生了什么吗?非常感谢任何帮助。


import {Component} from 'angular2/core';
const Mousetrap = require('mousetrap');
@Component({
  template: `
    视频模板:模式{{ mode }}
    
  `
})
export class Video {
  public mode: number;
  constructor() {
    this.mode = 0;
  }
  ngOnInit() {
    console.log('你好,视频组件');
    Mousetrap.bind('d', () => console.log('this.mode=', this.mode));
    Mousetrap.bind('i', () => this.incrementMode()); // 不起作用
    this.incrementMode(); // 起作用
    this.incrementMode(); // 起作用
    setTimeout(() => this.incrementMode(), 4000); // 起作用
  }
  incrementMode() {
    console.log('incMode', this.mode++);
  };
  ngOnDestroy() {
    console.log('再见,视频组件');
    Mousetrap.unbind(['d', 'i']);
  }
}

0
0 Comments

在Angular2中,当发生更改时,视图没有更新的问题可能是由于以下原因造成的:

问题在于Mousetrap库在Angular的zone之外创建了其实例。为了在每个异步事件之后触发变更检测,实例应该在Angular的zone内部实例化。有两种方法可以实现这一点:

1. 使用依赖注入:

bootstrap(App, [provide(Mousetrap, { useFactory: () => new Mousetrap() }) ]);
// ...
@Component({
  selector: 'my-app', 
  // ...
})
export class App {
  constructor(private mousetrap: Mousetrap) {
    // ...
  }
  //...
}

2. 在构造函数中直接创建Mousetrap实例:

@Component({
  selector: 'my-app', 
  // ...
})
export class App {
  constructor() {
    this.mousetrap = new Mousetrap();
    // ...
  }
  //...
}

无论哪种方式,您都可以像这样使用mousetrap实例:

ngOnInit() {
  this.mousetrap.bind('i', () => this.incrementMode()); // It works now!!!
  // ...
}

现在您不需要在每个bind调用中使用ngZone.run()了。如果使用依赖注入,您还可以在应用程序的任何组件/服务中使用此mousetrap实例,而不仅仅是在App组件中。

这是一个相当聪明的解决方案。它适用于每个/大多数库吗?

嗯,有太多使用绝对疯狂实现的JS库。所以我绝对不能保证这对每个/大多数库都适用。但基本原则很简单:您必须确保"与异步相关"的函数(例如addEventListener)在Angular zone内部调用即可。

谢谢您的解答。现在我终于理解Savkin的说法了:“Angular 2使用Zone.js来知道何时需要进行此检查。这意味着您不需要调用scope.$apply与第三方库集成。”-来自The Core Concepts of Angular 2博客文章的ZONES部分。我已经将其列入了我待解决/我不理解的列表中,很长时间了。(我假设Angular 2中Angular 1的scope.$apply的等效物是ApplicationRef.tick()。但是如果我们使用这种技术,我们就不需要它。)

不客气。我会说,Angular2的ApplicationRef.tick()在某种程度上相当于Angular1的$rootScope.$digest(),ngZone.run(cb)在某种程度上相当于$rootScope.$apply(cb),changeDetectorRef.detectChanges()在某种程度上相当于$scope.$digest()。

0
0 Comments

问题的出现原因:如果MouseTrap是Angular之外的东西,你可能需要注入NgZone并像这样运行你的代码。

问题的解决方法:使用NgZone注入并运行代码。

文章如下:

如果MouseTrap是Angular之外的东西,你可能需要注入NgZone并像这样运行你的代码。

Mousetrap.bind('i', () => this.ngZone.run(() => this.incrementMode()));

感谢关于NgZone的信息,我已经让它像这样工作了。

Mousetrap.bind('i', () => this.ngZone.run(() => this.incrementMode()));

感谢反馈 🙂 更新了我的答案。

0