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


Posted in Javascript onMay 10, 2020

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

问题描述

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

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

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

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

解决办法

既然生命周期函数没调用,我们让他调用不就行了,值已经变化了,但是界面不变化,说明,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组件显示的才会变化,如下图所示

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

总结

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

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

Javascript 相关文章推荐
分享精心挑选的23款美轮美奂的jQuery 图片特效插件
Aug 14 Javascript
JS正则表达式获取分组内容的方法详解
Nov 15 Javascript
jQuery对象与DOM对象之间的相互转换
Mar 03 Javascript
javascript图片滑动效果实现
Jan 28 Javascript
JavaScript学习笔记之创建对象
Mar 25 Javascript
BootStrap3学习笔记(一)之网格系统
May 20 Javascript
vue组件父子间通信之综合练习(聊天室)
Nov 07 Javascript
JS中的两种数据类型及实现引用类型的深拷贝的方法
Aug 12 Javascript
cordova+vue+webapp使用html5获取地理位置的方法
Jul 06 Javascript
原生JS实现顶部导航栏显示按钮+搜索框功能
Dec 25 Javascript
关于AngularJS中几种Providers的区别总结
May 17 Javascript
javascript进阶篇深拷贝实现的四种方式
Jul 07 Javascript
JavaScript 装逼指南(js另类写法)
May 10 #Javascript
js中!和!!的区别与用法
May 09 #Javascript
JS端基于download.js实现图片、视频时直接下载而不是打开预览
May 09 #Javascript
JS 获取文件后缀,判断文件类型(比如是否为图片格式)
May 09 #Javascript
js根据后缀判断文件文件类型的代码
May 09 #Javascript
Element实现表格嵌套、多个表格共用一个表头的方法
May 09 #Javascript
JS原形与原型链深入详解
May 09 #Javascript
You might like
写php分页时出现的Fatal error的解决方法
2011/04/18 PHP
PHP中file_exists与is_file,is_dir的区别介绍
2012/09/12 PHP
php中stdClass的用法分析
2015/02/27 PHP
PHP使用CURL实现多线程抓取网页
2015/04/30 PHP
启用Csrf后POST数据时出现的400错误
2015/07/05 PHP
php根据日期或时间戳获取星座信息和生肖等信息
2015/10/20 PHP
ThinkPHP 在阿里云上的nginx.config配置实例详解
2017/10/11 PHP
PHP正则判断一个变量是否为正整数的方法
2019/02/27 PHP
PHP设计模式之装饰器(装饰者)模式(Decorator)入门与应用详解
2019/12/13 PHP
tagName的使用,留一笔
2006/06/26 Javascript
JavaScript学习笔记(十七)js 优化
2010/02/04 Javascript
取消选中单选框radio的三种方式示例介绍
2013/12/23 Javascript
js函数模拟显示桌面.scf程序示例
2014/04/20 Javascript
Express作者TJ告别Node.js奔向Go
2014/07/14 Javascript
包含中国城市的javascript对象实例
2015/08/03 Javascript
javascript实现的猜数小游戏完整实例代码
2016/05/10 Javascript
javaScript给元素添加多个class的简单实现
2016/07/20 Javascript
javascript数组对象常用api函数小结(连接,插入,删除,反转,排序等)
2016/09/20 Javascript
vue学习笔记之指令v-text &amp;&amp; v-html &amp;&amp; v-bind详解
2017/05/12 Javascript
利用require.js与angular搭建spa应用的方法实例
2017/07/19 Javascript
node.js 核心http模块,起一个服务器,返回一个页面的实例
2017/09/11 Javascript
JavaScript重复元素处理方法分析【统计个数、计算、去重复等】
2017/12/14 Javascript
angularjs 页面自适应高度的方法
2018/01/17 Javascript
从零到一详聊创建Vue工程及遇到的常见问题
2019/04/25 Javascript
js回文数的4种判断方法示例
2019/06/04 Javascript
简述Vue中容易被忽视的知识点
2019/12/09 Javascript
解决vue 使用setTimeout,离开当前路由setTimeout未销毁的问题
2020/07/21 Javascript
在Python的setuptools框架下生成egg的教程
2015/04/13 Python
python使用PyGame绘制图像并保存为图片文件的方法
2015/04/24 Python
python 不同方式读取文件速度不同的实例
2018/11/09 Python
Python实现的调用C语言函数功能简单实例
2019/03/13 Python
python中温度单位转换的实例方法
2020/12/27 Python
美国高端牛仔品牌:Silver Jeans
2019/12/12 全球购物
必须要使用游标的SQL语句有那些
2012/05/07 面试题
优秀毕业生的求职信
2014/07/21 职场文书
在Java中Collection的一些常用方法总结
2021/06/13 Java/Android