在Angular2中,当视图发生变化时,视图不会自动更新。
在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']); } }
在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()。
问题的出现原因:如果MouseTrap
是Angular之外的东西,你可能需要注入NgZone
并像这样运行你的代码。
问题的解决方法:使用NgZone
注入并运行代码。
文章如下:
如果MouseTrap
是Angular之外的东西,你可能需要注入NgZone
并像这样运行你的代码。
Mousetrap.bind('i', () => this.ngZone.run(() => this.incrementMode()));
感谢关于NgZone
的信息,我已经让它像这样工作了。
Mousetrap.bind('i', () => this.ngZone.run(() => this.incrementMode()));
感谢反馈 🙂 更新了我的答案。