Skip to main content

Ionic 页面生命周期

本指南介绍了页面生命周期在使用 Ionic 和 Angular 构建的应用中如何工作。

¥This guide covers how the page life cycle works in an app built with Ionic and Angular.

Flowchart illustrating the Ionic page life cycle events and their sequence.

Angular 生命周期事件

¥Angular Life Cycle Events

Ionic 拥抱 Angular 提供的生命周期事件。你会发现最常用的两个 Angular 事件是:

¥Ionic embraces the life cycle events provided by Angular. The two Angular events you will find using the most are:

活动名称描述
ngOnInit在组件初始化期间触发一次。此事件可用于初始化本地成员并调用只需执行一次的服务。
ngOnDestroy在 Angular 破坏视图之前触发。对于清理很有用,比如取消订阅可观察对象。

有关 Angular 组件生命周期事件的更多信息,请访问他们的 组件生命周期文档

¥For more info on the Angular Component Life Cycle events, visit their component lifecycle docs.

注意

使用 ion-navion-router-outlet 的组件不应使用 OnPush 变更检测策略。这样做将阻止诸如 ngOnInit 之类的生命周期钩子触发。此外,异步状态更改可能无法正确渲染。

¥Components that use ion-nav or ion-router-outlet should not use the OnPush change detection strategy. Doing so will prevent lifecycle hooks such as ngOnInit from firing. Additionally, asynchronous state changes may not render properly.

Ionic 页面事件

¥Ionic Page Events

除了 Angular 生命周期事件之外,Ionic Angular 还提供了一些你可以使用的附加事件:

¥In addition to the Angular life cycle events, Ionic Angular provides a few additional events that you can use:

活动名称描述
ionViewWillEnter当组件路由即将动画进入视图时触发。
ionViewDidEnter当组件路由完成动画时触发。
ionViewWillLeave当组件路由即将动画时触发。
ionViewDidLeave当组件路由完成动画时触发。

这些生命周期仅在由路由直接映射的组件上调用。这意味着如果 /pageOne 映射到 PageOneComponent,则 Ionic 生命周期将在 PageOneComponent 上调用,但不会在 PageOneComponent 可能渲染的任何子组件上调用。

¥These lifecycles are only called on components directly mapped by a router. This means if /pageOne maps to PageOneComponent, then Ionic lifecycles will be called on PageOneComponent but will not be called on any child components that PageOneComponent may render.

ionViewWillEnterionViewDidEnter 之间的区别在于它们何时开火。前者在 ngOnInit 之后但页面转换开始之前触发,后者在转换结束后立即触发。

¥The difference between ionViewWillEnter and ionViewDidEnter is when they fire. The former fires right after ngOnInit but before the page transition begins, and the latter directly after the transition ends.

对于 ionViewWillLeaveionViewDidLeaveionViewWillLeave 在离开当前页面的转换开始之前被直接调用,而 ionViewDidLeave 直到新页面成功转换到之后(在新页面 ionViewDidEnter 触发之后)才会被调用。

¥For ionViewWillLeave and ionViewDidLeave, ionViewWillLeave gets called directly before the transition away from the current page begins, and ionViewDidLeave does not get called until after the new page gets successfully transitioned into (after the new pages ionViewDidEnter fires).

Animated GIF showing Ionic page life cycle events in a console log as a page transition occurs.

Ionic 如何处理页面的生命周期

¥How Ionic Handles the Life of a Page

Ionic 有其路由插座,称为 <ion-router-outlet />。该插座通过一些附加功能扩展了 Angular 的 <router-outlet />,以便为移动设备提供更好的体验。

¥Ionic has its router outlet, called <ion-router-outlet />. This outlet extends Angular's <router-outlet /> with some additional functionality to enable better experiences for mobile devices.

当应用封装在 <ion-router-outlet /> 中时,Ionic 对待导航的方式略有不同。当你导航到新页面时,Ionic 会将旧页面保留在现有 DOM 中,但将其从你的视图中隐藏并转换新页面。我们这样做的原因有两个:

¥When an app is wrapped in <ion-router-outlet />, Ionic treats navigation a bit differently. When you navigate to a new page, Ionic will keep the old page in the existing DOM, but hide it from your view and transition the new page. The reason we do this is two-fold:

  1. 我们可以维护旧页面的状态(屏幕上的数据、滚动位置等......)

    ¥We can maintain the state of the old page (data on the screen, scroll position, etc..)

  2. 我们可以提供返回页面的更平滑的过渡,因为它已经存在并且不需要重新创建。

    ¥We can provide a smoother transition back to the page since it is already there and doesn't need to be recreated.

仅当页面为 "popped" 时,才会从 DOM 中删除页面,例如,通过按 UI 中的后退按钮或浏览器后退按钮。

¥Pages are only removed from the DOM when they are "popped", for instance, by pressing the back button in the UI or the browsers back button.

由于这种特殊处理,ngOnInitngOnDestroy 方法可能不会在你通常认为应该触发的情况下触发。

¥Because of this special handling, the ngOnInit and ngOnDestroy methods might not fire when you would usually think they should.

ngOnInit 仅在每次新创建页面时触发,但在导航回页面时不会触发。例如,在选项卡界面中的每个页面之间导航只会调用每个页面的 ngOnInit 方法一次,而不会在后续访问中调用。ngOnDestroy 仅当页面 "popped" 时才会触发。

¥ngOnInit will only fire each time the page is freshly created, but not when navigated back to the page. For instance, navigating between each page in a tabs interface will only call each page's ngOnInit method once, but not on subsequent visits. ngOnDestroy will only fire when a page "popped".

路由守卫

¥Route Guards

在 Ionic 3 中,有一些额外的生命周期方法可用于控制何时可以进入页面 (ionViewCanEnter) 和离开页面 (ionViewCanLeave)。这些可用于保护页面免受未经授权的用户的侵害,并在你不希望用户离开时(例如在填写表单期间)将用户保留在页面上。

¥In Ionic 3, there were a couple of additional life cycle methods that were useful to control when a page could be entered (ionViewCanEnter) and left (ionViewCanLeave). These could be used to protect pages from unauthorized users and to keep a user on a page when you don't want them to leave (like during a form fill).

这些方法在 Ionic 4 中被删除,转而使用 Angular 的 Route Guards。

¥These methods were removed in Ionic 4 in favor of using Angular's Route Guards.

路由防护有助于确定是否可以针对路由采取特定操作。它们是实现特定接口的类。CanActivateCanDeactivate 接口可用于实现与已删除事件 ionViewCanEnterionViewCanLeave 相同类型的逻辑。

¥A route guard helps determine if a particular action can be taken against a route. They are classes that implement a certain interface. The CanActivate and CanDeactivate interfaces can be used to implement the same type of logic that the removed events ionViewCanEnter and ionViewCanLeave did.

@Injectable()
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService) {}

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
return this.authService.isAuthenticated();
}
}

要使用此防护,请将其添加到路由定义中的相应参数中:

¥To use this guard, add it to the appropriate param in the route definition:

{ path: 'settings', canActivate: [AuthGuard], loadChildren: '...',  }

有关如何使用路由防护的更多信息,请访问 Angular 的 路由文档

¥For more info on how to use route guards, go to Angular's router documentation.

每种生命周期方法的指南

¥Guidance for Each Life Cycle Method

以下是有关每个生命周期事件用例的一些提示。

¥Below are some tips on use cases for each of the life cycle events.

  • ngOnInit - 初始化你的组件并从不需要在每次后续访问时刷新的服务加载数据。

    ¥ngOnInit - Initialize your component and load data from services that don't need refreshing on each subsequent visit.

  • ionViewWillEnter - 由于每次导航到视图时都会调用 ionViewWillEnter(无论是否初始化),因此这是从服务加载数据的好方法。但是,如果你的数据在动画期间返回,它可能会启动大量 DOM 操作,这可能会导致一些动画卡顿。

    ¥ionViewWillEnter - Since ionViewWillEnter is called every time the view is navigated to (regardless if initialized or not), it's a good method to load data from services. However, if your data comes back during the animation, it can start lots of DOM manipulation, which can cause some janky animations.

  • ionViewDidEnter - 如果你在加载数据时发现使用 ionViewWillEnter 存在性能问题,则可以改为在 ionViewDidEnter 中进行数据调用。但是,只有在用户看到页面后才会触发此事件,因此你可能需要使用加载指示器或骨架屏幕,以便在转换完成后内容不会不自然地闪烁。

    ¥ionViewDidEnter - If you see performance problems from using ionViewWillEnter when loading data, you can do your data calls in ionViewDidEnter instead. This event won't fire until after the page is visible by the user, however, so you might want to use either a loading indicator or a skeleton screen, so content doesn't flash in un-naturally after the transition is complete.

  • ionViewWillLeave - 可用于清理,例如取消订阅可观察对象。由于从当前页面导航时 ngOnDestroy 可能不会触发,因此如果你不希望在屏幕未显示时激活清理代码,请将清理代码放在这里。

    ¥ionViewWillLeave - Can be used for cleanup, like unsubscribing from observables. Since ngOnDestroy might not fire when you navigate from the current page, put your cleanup code here if you don't want it active while the screen is not in view.

  • ionViewDidLeave - 当此事件触发时,你知道新页面已完全转换,因此当视图可见时你通常不会执行的任何逻辑都可以转到此处。

    ¥ionViewDidLeave - When this event fires, you know the new page has fully transitioned in, so any logic you might not normally do when the view is visible can go here.

  • ngOnDestroy - 你不想在 ionViewWillLeave 中清理的页面的清理逻辑。

    ¥ngOnDestroy - Cleanup logic for your pages that you don't want to clean up in ionViewWillLeave.