angula中使用iframe点击后不执行变动检测

这个问题是上周的,当时以为这个问题的解决办法太简单了,不用写博客记录,可是潘老师今天今天又遇到了须要使用这个的地方,感受问题虽然不难,可是,写篇博客,方便本身查询,也给了其余人搜索到解决办法的机会。html

问题描述

项目中使用到了ifame,理想状态是:当点击ifame中的按钮时,将会调用经过angular写的一个函数,函数将会修改一个ngif的判断条件,显示一个弹窗,
但现实是:当点击ifame中的按钮时,将会调用经过angular写的一个函数,函数将会修改一个ngif的判断条件,而后就没有而后了.
image.pngtypescript

开始的时候本身直接懵了, 方法确实执行了, 但界面没修改, 问了问潘老师, 潘老师说看看生命周期函数是否执行了, 果真, 全部的生命周期函数都没有调用。segmentfault

解决办法

既然生命周期函数没调用,咱们让他调用不就好了,值已经变化了,可是界面不变化,说明,angular 不知道值变化了,因此咱们可让angular 主动进行变动检测,让它知道已经发生了变化。
对此咱们可使用ChangeDetectorRefpromise

变化监测类 - ChangeDetectorRef

Angular 在整个运行期间都会为每个组件建立 ChangeDetectorRef 的实例,该实例提供了相关方法来手动管理变化监测。有了这个类,咱们本身就能够自定义组件的变化监测策略了,如中止/启用变化监测或者按指定路径变化监测等等。

它有如下方法:浏览器

  • markForCheck():把根组件到该组件之间的这条路径标记起来,通知Angular在下次触发变化监测时必须检查这条路径上的组件。
  • detach():从变化监测树中分离变化监测器,该组件的变化监测器将再也不执行变化监测,除非再次手动执行reattach()方法。
  • reattach():把分离的变化监测器从新安装上,使得该组件及其子组件都能执行变化监测。
  • detectChanges():手动触发执行该组件到各个子组件的一次变化监测。

因此,咱们可使用detectChanges()来达到目标app

使用方法

// 在组件中注入
  constructor(private changeDetectorRef: ChangeDetectorRef) {
  }
  
  // 直接使用
  test() {
    this.changeDetectorRef.detectChanges()
  }

angular什么时候进行变化检测

总结起来, 主要有以下几种状况:异步

  • 用户输入操做,好比点击,提交等
  • 请求服务端数据(XHR)
  • 定时事件,好比setTimeoutsetInterval

Angular并非捕捉对象的变更,它采用的是在适当的时机去检验对象的值是否被改动,这个时机就是这些异步事件的发生。
这个时机是由 Zone.js去掌控的,它获取到了整个应用的执行上下文,可以对相关的异步事件发生、完成或者异常等进行捕获,而后驱动 Angular 的变化监测机制执行。函数

Zone.js的做用

实际上Zone,js有一个叫猴子补丁的东西。在Zone.js运行时,就会为这些异步事件作一层代理包裹,也就是说Zone.js运行后,调用setTimeout、addEventListener等浏览器异步事件时,再也不是调用原生的方法,而是被猴子补丁包装事后的代理方法。代理里setup了钩子函数, 经过这些钩子函数, 能够方便的进入异步任务执行的上下文.this

//如下是Zone.js启动时执行逻辑的抽象代码片断
function zoneAwareAddEventListener() {...}
function zoneAwareRemoveEventListener() {...}
function zoneAwarePromise() {...}
function patchTimeout() {...}
window.prototype.addEventListener=zoneAwareAddEventListener;
window.prototype.removeEventListener=zoneAwareRemoveEventListener;
window.prototype.promise = zoneAwarePromise;
window.prototype.setTimeout = patchTimeout;

关于Zone.js的详细内容能够看这篇文章spa

angular变化检测策略

angular 提供了两种变动检测策略,除了上述得Default外还有一种OnPush 的检测机制

OnPush 与 Default 之间的差异: 当检测到与子组件输入绑定的值没有发生改变时,变化检测就不会深刻到子组件中去

一个OnPush的例子

app.comonent.ts

@Component({
  selector: 'app-root',
  template: `
    <h1>{{title}}</h1>
    <h2>user.name: {{user.name}}</h2>
    <button type="button" (click)="changeUserName()"> 改变属性
    </button>
    <button type="button" (click)="changeUserObject()">
      改变对象
    </button>
    <app-test [user]="user"></app-test>
  `,
})
export class AppComponent {
  title = 'OnPush Demo';
  user: User = new User({name: 'yunzhi'});

  changeUserName() {
    this.user.name = 'new name';
  }

  changeUserObject() {
    this.user = new User({name: 'new user'});
  }
}

test.component.ts

@Component({
  selector: 'app-test',
  template: `
    <div>
      <h3>test 组件</h3>
      <p>
        <label>User:</label>
        <span>{{user.name}}</span>
      </p>
    </div>`,
  // 使用OnPush模式只须要加上下面这段代码
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class TestComponent implements OnInit {
  @Input() user: User;

  constructor() {
  }

  ngOnInit() {
  }

}

这时当咱们点击改变属性按钮时test组件显示的并不会变化,只有改变user得引用test组件显示的才会变化,以下图所示
2020年05月09日-屏幕视频-14时55分15秒.gif

总结

原本觉得这个问题没什么可写的,直接解决好像就完事了,但没想到写着写着感受能写的愈来愈多,好比变动检测的顺序,还有ExpressionChangedAfterItHasBeenCheckedError都是应该知道的问题
,可是感受这些和主题又没有什么关系,想了想仍是算了。

参考文章

Angular开发实践(五):深刻解析变化监测
Angular系列之变化检测(Change Detection)

相关文章
相关标签/搜索