1

我在我的 angular2 应用程序中遇到了一个非常有趣的问题,我在这里简化了情况。

这是 AppComponnet

export class AppComponent {

    tabs: any = [];

    viewModes = [
       { label: "列表查看"},
       { label: "树状图" },
    ];


   constructor(private changeRef: ChangeDetectorRef) {}

   addTab() {
      var worker = new Worker("worker.js");
      worker.postMessage("");
      worker.onmessage = (event) => {
      this.tabs.push({
         label: 'label'
      })
     this.changeRef.detectChanges();
    }
  }

  currentMode: any;
  selectViewMode(mode: any) {
      if (this.currentMode) {
         this.currentMode.selected = false;
      }
      mode.selected = true;
      this.currentMode = mode;
   }

 }

这是模板

    <div *ngFor="let tab of tabs">
        <ul>
           <li *ngFor="let item of viewModes">
                <a (click)="selectViewMode(item)"     [style.background]="item.selected ? '#f69c55' : ''"> {{item.label}} </a>
           </li>
        </ul>
     </div>

     <button (click)="addTab()">Add Tab</button>

工人完成后,我将一个新标签推送到标签。并且 Angular2 在 Worker onmessage 回调之后不会进行更改检测,我必须手动触发更改检测。

但是在那之后,点击后添加的选项卡中列表的背景不会改变(回调函数被执行,所以改变检测不起作用)。

如果我执行其他操作,例如再次单击“添加选项卡”按钮,更改检测将起作用并按预期设置列表背景。

如果我不手动触发更改检测。按下选项卡后,执行其他操作(例如再次单击按钮)以触发更改检测。现在列表将显示,并且背景更改效果很好。

我知道关键是在 Worker 执行后手动调用更改检测,但我不知道详细发生了什么导致列表背景更改检测不起作用。

4

2 回答 2

2

每次调用 add tab 函数时,您都在调用一个新的工作人员。

addTab() {
      var worker = new Worker("worker.js");

相反,将顶部的工作人员声明为该类的范围绑定变量并在函数中使用它。

 worker : any = new Worker("worker.js");
    addTab() {
      this.worker.postMessage("");
      this.worker.onmessage = (event) => {
      this.tabs.push({
         label: 'label'
      })
于 2017-01-20T07:53:44.510 回答
1

NgZone修补异步 API,例如setTimeoutaddEventListener. 当调用此类 API 的回调时,Angular 会识别它并运行更改检测。

显然worker.onmessage不被 覆盖NgZone,因此不会调用更改检测。

有不同的方法来调用变更检测手动触发Angular2变更检测

detectChanges()仅调用当前元素的更改检测。如果模型更改具有更广泛的影响(在您的组件之外),那么您可能需要运行应用程序范围的更改检测(例如,如果您router.navigate()从在 Angulars 区域之外运行的回调中运行(未涵盖)NgZone。在这种情况下,您可以制作代码在区域内运行

ngZone.run(_ => { router.navigate(); }
于 2017-01-20T07:36:46.117 回答