angula中使用iframe点击后不执行变更检测的问题

这个问题是上周的,当时觉得这个问题的解决办法太简单了,不用写博客记录,但是潘老师今天今天又遇到了需要使用这个的地方,感觉问题虽然不难,但是,写篇博客,方便自己查询,也给了其他人搜索到解决办法的机会。

问题描述

项目中使用到了ifame,理想状态是:当点击ifame中的按钮时,将会调用通过angular写的一个函数,函数将会修改一个ngif的判断条件,显示一个弹窗,

但现实是:当点击ifame中的按钮时,将会调用通过angular写的一个函数,函数将会修改一个ngif的判断条件,然后就没有然后了.

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

解决办法

既然生命周期函数没调用,我们让他调用不就行了,值已经变化了,但是界面不变化,说明,angular 不知道值变化了,所以我们可以让angular 主动进行变更检测,让它知道已经发生了变化。

对此我们可以使用 ChangeDetectorRef

变化监测类 - ChangeDetectorRef

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

它有以下方法:

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

所以,我们可以使用 detectChanges() 来达到目标

使用方法

// 在组件中注入
 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了钩子函数, 通过这些钩子函数, 可以方便的进入异步任务执行的上下文

//以下是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 的详细内容可以看 这篇文章

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组件显示的才会变化,如下图所示

总结

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

到此这篇关于angula中使用iframe点击后不执行变更检测的问题的文章就介绍到这了,更多相关angula iframe 变更检测内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • angular中如何绑定iframe中src的方法

    需求: 页面中有一个网页组件(由iframe编写),此iframe显示在一个输入框中,当修改输入框中地址的时候,要求改变网页组件中的内容 网页组件中的代码(html的部分) <iframe #Iframe [src]="testUrl" frameborder="0" width="100%" height="100%"> </iframe> 网页组件中的代码(ts的部分) ...省略 export c

  • AngularJS iframe跨域打开内容时报错误的解决办法

    <iframe id="myFrame" ng-src="{{url}}" width="100%" height="100%" seamless frameborder="0" ></iframe> 打开不同域的内容时报下面的错误: Blocked loading resource from url not allowed by $sceDelegate policy 解决方案:

  • angula中使用iframe点击后不执行变更检测的问题

    这个问题是上周的,当时觉得这个问题的解决办法太简单了,不用写博客记录,但是潘老师今天今天又遇到了需要使用这个的地方,感觉问题虽然不难,但是,写篇博客,方便自己查询,也给了其他人搜索到解决办法的机会. 问题描述 项目中使用到了ifame,理想状态是:当点击ifame中的按钮时,将会调用通过angular写的一个函数,函数将会修改一个ngif的判断条件,显示一个弹窗, 但现实是:当点击ifame中的按钮时,将会调用通过angular写的一个函数,函数将会修改一个ngif的判断条件,然后就没有然后了.

  • Angular2学习教程之ng中变更检测问题详解

    开发中遇到的问题 在开发中遇到一个这样的问题,代码不便透露,这里用简单的例子还原一下问题所在: 有三个组件,第一个是用来展示Todo列表的组件TodoComponent,Todo是个类,包含id和name属性. @Component({ selector: 'todo-list', template: ` <p *ngFor='let item of todos'>{{ item.name }}</p> `, }) export class TodoComponent{ @Inpu

  • 用hta+javascript实现替换网站被下木马网页中的iframe

    服务器中了病毒是件超级麻烦的事情,尤其是什么熊猫烧香之类的或者变种病毒,因为它们不单单潜伏于计算机里,还会把所有的一些网页文件加上了一些iframe,让访问者继续中毒,我想这也是它得已迅速蔓延的手段吧!     如果要把网页中的iframe去掉,是件吃力的苦力活.     所以,写了这样的一个小工具,希望能起到一点点的作用.      请把代码复制,保存在本地,以hta为扩展名.然后双击执行 复制代码 代码如下: <html> <head> <hta:application 

  • 用JS操作FRAME中的IFRAME及其内容的实现代码

    问:想通过在地址栏输入一段JS来设置一下页面里某个FRAME中的IFRAME的URL和里面某个TEXT的值,然后点击提交按钮.注意:页面是其它网站的,不要给出一些改动页面代码的答案.具体情况如下: 主页面.htm: view plaincopy to clipboardprint? <FRAMESET border=0 frameSpacing=0 frameBorder=0 cols=*,1005,*> <FRAME src="blank.html" frameBo

  • Jquery中获取iframe的代码

    父窗口中操作iframe:window.frames["iframeChild"].document //假如iframe的id为iframeChild 在子窗口中操作父窗口:window.parent.document 那么,用如果想用jquery的方法,我们怎么用jquery来获取iframe呢?下面是一下收集来的方法. 获取页面的对象其实就是dom方法外面加上jquery的选择符: 父窗口中操作iframe:$(window.frames["iframeChild&qu

  • JavaScript中关于iframe滚动条的去除和保留

    在开发中经常遇到去掉全部的滚动条,去掉右边的滚动条且保留底下的滚动条,去掉底下的滚动条且保留右边的滚动条,大家基于js是怎么实现的呢?下面通过本文给大家介绍下JavaScript中关于iframe滚动条的去除和保留的实现方法.一起看看吧! iframe嵌入页面后,我们有时需要调整滚动条,例如,去掉全部的滚动条,去掉右边的滚动条且保留底下的滚动条,去掉底下的滚动条且保留右边的滚动条.那么我们应该怎么做呢?    一:去掉全部的滚动条 第一个方法:   iframe 有一个scrolling属性,它

  • PHP中如何判断exec函数执行成功?

    前言 做一个代码发布的系统,需要用到PHP的exec函数来执行Linux下的命令和git,svn命令,如何判断PHP的exec函数是否执行成功呢? 解决方案 写个PHP文件来做实验: exec函数第一个参数是执行的命令,第二个参数是执行的结果,第三个参数是执行的状态. <?php exec('ls', $log, $status); print_r($log); print_r($status); echo PHP_EOL; 执行这个php文件: 这里$log,$status输出结果如图. 但是

  • vue组件中使用iframe元素的示例代码

    本文介绍了vue组件中使用iframe元素的示例代码,分享给大家,具体如下: 需要在本页面中展示vue组件中的超链接,地址栏不改变的方法: <template> <div class="accept-container"> <div class="go-back" v-show="goBackState" @click="goBack">GoBack</div> <ul&g

  • layer弹出的iframe层在执行完毕后关闭当前弹出层的方法

    如下所示: 这种弹出层在ajax执行完添加房间的动作后在回调里写 var index = parent.layer.getFrameIndex(window.name); setTimeout(function(){parent.layer.close(index)}, 1000); 1秒后,当前窗口就会关闭了 以上这篇layer弹出的iframe层在执行完毕后关闭当前弹出层的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • 对for循环中表达式和循环体的执行顺序详解

    对于学c的朋友来说,for循环可能使我们经常用到的一种循环语句 for(表达式1:表达式2:表达式3){循环体} 知道其的语句执行顺序对我们来说可以避免很多失误 我们可以利用下面这个小程序轻易测出其内在的语句循环顺序: #include<stdio.h> void main() { int i; for (printf("#1\n"),i=1; printf("#2\n"),i<=5; printf("#3\n"),i++) {

随机推荐