开发一个网站需要几个人,软件设计属于什么专业,优化推广seo,法律行业做的比较好的平台网站前段时间遇到这样一个 bug#xff0c;通过一个 click 事件跳转到一个新页面#xff0c;新页面迟迟不加载#xff1b; 经过多次测试发现#xff0c;将鼠标移入某个 tab #xff0c;页面就加载出来了。
举个例子#xff0c;页面内容无法加载#xff0c;但是将鼠标移入下图…前段时间遇到这样一个 bug通过一个 click 事件跳转到一个新页面新页面迟迟不加载 经过多次测试发现将鼠标移入某个 tab 页面就加载出来了。
举个例子页面内容无法加载但是将鼠标移入下图的 消息 或者 历史 tab页面就加载出来了。 正常情况下Angular 会在 组件初始化完毕后 自动进行变更检测并更新视图。
但有时候你可能希望在 组件实例化后 立即执行一次变更检测以确保视图能够及时更新。这种情况下我们可以在构造函数之后的代码中显式调用 detectChanges() 方法。
为了在切换路由后立即进行 变更检测 并渲染新页面在路由导航结束后Angular 提供了一个 Router.events 事件流来监听路由导航的状态。开发者可以订阅 NavigationEnd 事件并在回调函数中调用 detectChanges() 方法。
import { Component, OnInit, ChangeDetectorRef } from angular/core;
import { Router, NavigationEnd } from angular/router;Component({// 组件元数据
})
export class MyComponent implements OnInit {constructor(private router: Router,private cdr: ChangeDetectorRef,) {}ngOnInit() {this.router.events.subscribe(event {if (event instanceof NavigationEnd) {this.cdr.detectChanges(); // 在路由切换完成后调用 detectChanges}});}}如此就实现了跳转页面视图不展示的问题。
这里简单介绍一下 Angular 的变更检测策略包括 默认策略、OnPush 策略 和 无策略。
要关闭变更检测可以将变更检测策略设置为 无策略 ChangeDetectionStrategy.OnPush或 手动调用 detach() 方法来分离变更检测器。
1 变更检测策略
1.1 手动分离变更检测器
使用 detach() 方法来分离变更检测器这样组件就不再与变更检测关联。
import { Component, OnInit, ChangeDetectorRef } from angular/core;Component({selector: app-my-component,templateUrl: ./my-component.component.html
})
export class MyComponent implements OnInit {constructor(private cdr: ChangeDetectorRef) {}ngOnInit() {this.cdr.detach(); // 分离变更检测器}
}在此方法中我们需要将 ChangeDetectorRef 注入到组件中并在 ngOnInit 生命周期钩子函数中调用 detach() 方法。这样就会分离变更检测器从而关闭变更检测。
1.2 使用变更检测策略
将组件的变更检测策略设置为 ChangeDetectionStrategy.OnPush这会使得组件仅在输入属性发生变化时才进行变更检测。我们可以在组件的元数据中指定变更检测策略。
import { Component, ChangeDetectionStrategy } from angular/core;Component({selector: app-my-component,templateUrl: ./my-component.component.html,changeDetection: ChangeDetectionStrategy.OnPush // 设置变更检测策略为 OnPush
})
export class MyComponent {}使用此策略时我们需要手动触发变更检测例如通过注入 ChangeDetectorRef 并调用 detectChanges() 方法。
需要注意的是关闭变更检测可能导致视图无法及时更新因此应仔细考虑是否真正需要关闭变更检测。一般情况下使用默认的变更检测策略并让 Angular 自动执行变更检测是推荐的做法。只有在特定的性能优化需求下才应该考虑手动关闭变更检测。
2 ChangeDetectionStrategy.OnPush 策略
这里我们要注意将组件的变更检测策略设置为 ChangeDetectionStrategy.OnPush这会使得组件仅在 输入属性 发生变化时才进行变更检测。输入属性指的是通过 Input 装饰器定义在组件上的属性。这些属性用于从父组件向子组件传递数据。
当将组件的变更检测策略设置为 ChangeDetectionStrategy.OnPush 时组件只会在 输入属性 发生变化时才触发变更检测和重新渲染。
举个例子MyComponent 的组件定义了一个输入属性 data只有每次 data 的值发生变化 Angular 才会自动触发变更检测并更新组件的视图。
import { Component, Input, ChangeDetectionStrategy } from angular/core;Component({selector: app-my-component,template: div{{ data }}/div,changeDetection: ChangeDetectionStrategy.OnPush // 设置变更检测策略为 OnPush
})
export class MyComponent {Input() data: string;
}
通过将组件的变更检测策略设置为 ChangeDetectionStrategy.OnPush我们可以确保只有父组件修改了子组件的输入属性或者父组件手动调用 markForCheck() 方法子组件才会执行变更检测、重新渲染如此可以提高性能并减少不必要的变更检测。
事实上除了输入属性发生变化组件自身的事件例如按钮点击、定时器等也可以触发变更检测
注意当只有子组件内部的变量值发生改变而没有其他触发条件满足时ChangeDetectionStrategy.OnPush 策略下的组件不会自动触发变更检测。这意味着组件的视图不会被更新。
2.1 子组件 ngModule 值变化
这里可能会有人提问子组件的 ngModule 值变化会不会触发子组件的变更检测和重新渲染。
答案是不会ngModule 是 Angular 中用于定义模块的装饰器函数它通常在应用程序的根模块中使用并且在启动时就确定了它的变化不会被视为触发变更检测的条件。
子组件input框的 ngModule 值发生变化时并不能直接触发子组件的变更检测那么 input 框中内容会发生变化吗 当 input 框的 ngModule 值发生变化时输入框中的内容仍然会根据新的值进行更新因为这是由 ngModel 实现的。这种更新是通过 DOM 事件如 input 或 change来触发的而不是通过 Angular 的变更检测系统。
2.2 子组件 内部数据发生变化
这里举一个内部数据发生变化的例子。
使用 ChangeDetectionStrategy.OnPush 策略
count 的值定时发生变化但是页面并未更新
import { ChangeDetectorRef, ChangeDetectionStrategy } from angular/core;Component({selector: test,templateUrl: ./test.component.html,styleUrls: [./test.component.less],changeDetection: ChangeDetectionStrategy.OnPush,
})export class TestComponent implements OnInit, OnDestroy {constructor(private router: Router,private cdr: ChangeDetectorRef,) { }count 1;ngOnInit(): void {setInterval(() {this.count;}, 1000);}
}不使用 ChangeDetectionStrategy.OnPush 策略
页面数据会刷新 2.3 父组件传值发生变化
父组件传值直接修改了可变对象如数组、对象等而没有创建一个新的引用那么组件可能无法检测到这个改变从而不会触发变更检测。
items: string[] [Item 1, Item 2, Item 3];
this.items.push(New Item);3 关闭变更检测
在 Angular 中我们可以通过使用 ChangeDetectorRef 来关闭或禁用变更检测。ChangeDetectorRef 是一个服务提供了与变更检测相关的方法。以下是一种关闭变更检测的方法
注入 ChangeDetectorRef 服务
import { Component, ChangeDetectorRef } from angular/core;Component({selector: app-example,template: !-- Your components template --
})
export class ExampleComponent {constructor(private cdr: ChangeDetectorRef) {}
}
在需要关闭变更检测的地方调用 detach() 方法
this.cdr.detach();调用 detach() 方法会将组件从变更检测树中分离意味着该组件及其子组件将不再进行自动的变更检测和视图更新。这可以帮助减少不必要的计算和渲染提高性能。
需要注意的是一旦你将组件从变更检测树中分离它将不再自动响应输入属性的变化或事件的触发。如果你需要手动控制变更检测可以使用 markForCheck() 方法来通知 Angular 运行变更检测。例如
this.cdr.markForCheck();使用 markForCheck() 方法可以标记组件及其父组件使其在下一次变更检测周期中进行变更检测。
总结起来通过 ChangeDetectorRef 的 detach() 方法我们可以关闭变更检测以提高性能并使用 markForCheck() 方法手动触发变更检测。请注意在大多数情况下不需要手动关闭变更检测Angular 的默认行为通常已经足够高效和准确。 this.cdr.markForCheck()和this.cdr.detectChanges()是Angular中的变更检测相关方法它们有一些区别和适用场景。 this.cdr.markForCheck(): 调用markForCheck()方法会通知 Angular 在下一次变更检测周期中检查组件及其子组件并执行相应的变更检测操作。该方法将标记组件为“已脏”dirty意味着组件可能发生了变化需要进行检查。这对于在组件中进行异步操作但可能没有直接触发变更的情况非常有用。调用markForCheck()方法本身不会立即触发变更检测而是等待下一次变更检测周期执行。 this.cdr.detectChanges(): 调用detectChanges()方法会立即触发一次变更检测无论组件是否已被标记为“脏”。这将从组件树的根节点开始进行变更检测并检查任何已标记为“脏”的组件。这可以用来强制立即进行变更检测而不必等待下一次自动变更检测周期。但是过度使用detectChanges()方法可能会导致性能问题因为它执行了全面的变更检测而不只是对标记为“脏”的组件进行检查。 从使用角度来看通常情况下应该优先使用this.cdr.markForCheck()方法因为它更高效且更符合 Angular 的变更检测机制。只有在特殊情况下如在组件中调用了异步操作但未触发变更时才应该使用this.cdr.detectChanges()方法来强制立即进行变更检测。