在 Uni-App 开发过程中,生命周期 是每个开发者需要深刻理解的核心概念。通过对生命周期的掌握,我们可以在应用的不同阶段执行特定的逻辑,从而优化应用性能、提升用户体验。本文将从应用、页面和组件的生命周期三个层面,详细解读 Uni-App 中的生命周期,并结合实际代码展示其用法。
一、生命周期概述
生命周期 类似于人的生命周期,从创建、挂载、更新到销毁。在 Uni-App 中,每个组件、页面和整个应用都有各自的生命周期方法,开发者可以在这些方法中执行初始化、数据获取、清理等操作。
生命周期分类
- 应用生命周期:作用于整个应用,仅在应用启动和关闭时触发。
- 页面生命周期:作用于单个页面,每个页面在加载、显示、隐藏和卸载时触发。
- 组件生命周期:作用于自定义组件,每个组件在创建、挂载、更新和销毁时触发。
二、应用生命周期
应用生命周期方法定义在 App.vue
文件中,仅在应用的整个生命周期中触发一次或多次。
常用应用生命周期方法
- onLaunch:应用初始化完成时触发,仅触发一次。
- onShow:应用启动时或从后台进入前台时触发。
- onHide:应用从前台进入后台时触发。
- onError:应用发生错误时触发。
- onUnhandledRejection:应用未捕获的 Promise 拒绝时触发。
示例代码
App.vue
<template> <router-view></router-view> </template> <script> export default { onLaunch() { console.log('应用初始化完成:onLaunch'); // 在此处进行全局初始化操作,如获取用户登录状态 }, onShow() { console.log('应用显示:onShow'); // 应用从后台回到前台时的操作 }, onHide() { console.log('应用隐藏:onHide'); // 应用进入后台时的操作 }, onError(error) { console.log('应用发生错误:', error); // 处理全局错误 }, onUnhandledRejection(reason, promise) { console.log('未处理的 Promise 拒绝:', reason); // 处理未捕获的 Promise 拒绝 } } </script> <style> /* 全局样式 */ </style>
解析
- onLaunch:应用启动时执行一次,适合进行全局初始化操作,如设置全局变量、获取用户登录状态等。
- onShow:每次应用显示时触发,包括首次启动和从后台回到前台。
- onHide:每次应用隐藏时触发,即应用进入后台。
- onError:应用发生错误时触发,可以用于全局错误处理。
- onUnhandledRejection:未捕获的 Promise 拒绝时触发,用于处理异步操作中的错误。
三、页面生命周期
页面生命周期方法定义在各个页面的 .vue
文件中,每个页面在加载、显示、隐藏和卸载时触发。
常用页面生命周期方法
- onLoad:页面加载时触发,接收页面参数。
- onReady:页面初次渲染完成时触发。
- onShow:页面显示时触发,每次页面显示都会触发。
- onHide:页面隐藏时触发,每次页面隐藏都会触发。
- onUnload:页面卸载时触发,如使用
redirectTo
关闭页面时。
示例代码
pages/index/index.vue
<template> <view class="container"> <button @click="toggleComponent">显示/隐藏组件</button> <button @click="openNewPage">打开新页面</button> <!-- 使用 v-if 控制组件的显示与隐藏 --> <Test v-if="showComponent"></Test> <text>{{ message }}</text> </view> </template> <script> import Test from '@/components/Test.vue' export default { components: { Test }, data() { return { showComponent: false, message: '首页' } }, onLoad() { console.log('页面加载:onLoad'); // 页面初始化操作,如请求数据 }, onReady() { console.log('页面渲染完成:onReady'); // 页面渲染完成后的操作 }, onShow() { console.log('页面显示:onShow'); // 页面显示时的操作 }, onHide() { console.log('页面隐藏:onHide'); // 页面隐藏时的操作 }, onUnload() { console.log('页面卸载:onUnload'); // 页面卸载时的操作 }, methods: { toggleComponent() { this.showComponent = !this.showComponent; }, openNewPage() { uni.navigateTo({ url: '/pages/test-a/test-a' }); // 或者使用 redirectTo 关闭当前页面 // uni.redirectTo({ // url: '/pages/test-a/test-a' // }); } } } </script> <style> .container { padding: 20rpx; } button { margin-bottom: 20rpx; } </style>
pages/test-a/test-a.vue
<template> <view class="container"> <button @click="goBack">返回首页</button> <text>{{ message }}</text> </view> </template> <script> export default { data() { return { message: '测试页面 A' } }, onLoad() { console.log('测试页面 A 加载:onLoad'); // 页面初始化操作 }, onReady() { console.log('测试页面 A 渲染完成:onReady'); // 页面渲染完成后的操作 }, onShow() { console.log('测试页面 A 显示:onShow'); // 页面显示时的操作 }, onHide() { console.log('测试页面 A 隐藏:onHide'); // 页面隐藏时的操作 }, onUnload() { console.log('测试页面 A 卸载:onUnload'); // 页面卸载时的操作 }, methods: { goBack() { uni.navigateBack(); } } } </script> <style> .container { padding: 20rpx; } button { margin-bottom: 20rpx; } </style>
解析
- onLoad:页面加载时触发,可用于接收参数和进行初始化操作。
- onReady:页面首次渲染完成时触发,适合进行界面相关的操作,如动画效果。
- onShow:每次页面显示时触发,包括首次显示和从后台返回前台。
- onHide:每次页面隐藏时触发,如打开新页面或切换到其他应用。
- onUnload:页面被卸载时触发,如使用
redirectTo
关闭页面。
生命周期触发顺序示例
-
首次打开首页
- 应用生命周期:
onLaunch
onShow
- 页面生命周期:
onLoad
onShow
onReady
- 组件生命周期(首次显示时加载组件):
beforeCreate
created
mounted
- 应用生命周期:
-
点击“显示/隐藏组件”按钮
- 显示组件时:
beforeCreate
created
mounted
- 隐藏组件时:
destroyed
- 显示组件时:
-
点击“打开新页面”按钮,使用
navigateTo
- 当前页面生命周期:
onHide
(首页被隐藏)
- 新页面生命周期:
onLoad
onShow
onReady
- 当前页面生命周期:
-
返回首页
- 新页面生命周期:
onHide
(新页面被隐藏)
- 首页生命周期:
onShow
- 新页面生命周期:
-
使用
redirectTo
打开新页面- 当前页面生命周期:
onUnload
(首页被卸载)
- 新页面生命周期:
onLoad
onShow
onReady
- 当前页面生命周期:
四、组件生命周期
组件生命周期方法定义在自定义组件的 .vue
文件中,每个组件在创建、挂载、更新和销毁时触发。理解和正确使用这些方法,可以有效管理组件的状态和资源。
常用组件生命周期方法
- beforeCreate:实例初始化之后,数据观测和事件配置之前调用。
- created:实例创建完成后立即调用,此时已完成数据观测、属性和方法的运算,但挂载阶段尚未开始。
- beforeMount:在挂载开始之前调用,此时模板已编译但未挂载。
- mounted:组件挂载到页面后立即调用,此时可以进行 DOM 操作。
- beforeUpdate:数据更新之前调用,可以在此对数据进行处理。
- updated:数据更新后调用,此时 DOM 已更新。
- activated:用于
<keep-alive>
缓存组件的激活时调用。 - deactivated:用于
<keep-alive>
缓存组件的停用时调用。 - destroyed:组件实例销毁后调用,用于清理资源。
示例代码
1. 创建自定义组件 Test.vue
首先,在项目根目录下新建一个 components
文件夹,并在其中创建 Test.vue
组件。
components/Test.vue
<template> <view class="test-container"> <text>{{ message }}</text> </view> </template> <script> export default { name: 'Test', data() { return { message: '这是一个测试组件' } }, beforeCreate() { console.log('组件生命周期:beforeCreate'); }, created() { console.log('组件生命周期:created'); }, mounted() { console.log('组件生命周期:mounted'); }, destroyed() { console.log('组件生命周期:destroyed'); } } </script> <style> .test-container { padding: 20rpx; background-color: #f0f0f0; border: 1px solid #ccc; } </style>
2. 在页面中引用组件
接下来,在某个页面(如 pages/index/index.vue
)中引用并使用该组件。
pages/index/index.vue
<template> <view class="container"> <button @click="toggleComponent">显示/隐藏组件</button> <button @click="openNewPage">打开新页面</button> <!-- 使用 v-if 控制组件的显示与隐藏 --> <Test v-if="showComponent"></Test> <text>{{ message }}</text> </view> </template> <script> import Test from '@/components/Test.vue' export default { components: { Test }, data() { return { showComponent: false, message: '首页' } }, onLoad() { console.log('页面加载:onLoad'); }, onReady() { console.log('页面渲染完成:onReady'); }, onShow() { console.log('页面显示:onShow'); }, onHide() { console.log('页面隐藏:onHide'); }, onUnload() { console.log('页面卸载:onUnload'); }, methods: { toggleComponent() { this.showComponent = !this.showComponent; }, openNewPage() { uni.navigateTo({ url: '/pages/test-a/test-a' }); // 或者使用 redirectTo 关闭当前页面 // uni.redirectTo({ // url: '/pages/test-a/test-a' // }); } } } </script> <style> .container { padding: 20rpx; } button { margin-bottom: 20rpx; } </style>
3. 创建新页面 Test-a.vue
在 pages
目录下创建 test-a
文件夹,并在其中创建 test-a.vue
页面。
pages/test-a/test-a.vue
<template> <view class="container"> <button @click="goBack">返回首页</button> <text>{{ message }}</text> </view> </template> <script> export default { data() { return { message: '测试页面 A' } }, onLoad() { console.log('测试页面 A 加载:onLoad'); }, onReady() { console.log('测试页面 A 渲染完成:onReady'); }, onShow() { console.log('测试页面 A 显示:onShow'); }, onHide() { console.log('测试页面 A 隐藏:onHide'); }, onUnload() { console.log('测试页面 A 卸载:onUnload'); }, methods: { goBack() { uni.navigateBack(); } } } </script> <style> .container { padding: 20rpx; } button { margin-bottom: 20rpx; } </style>
解析
- beforeCreate:在组件实例化后、数据观测和事件配置之前调用。
- created:组件实例创建完成后调用,此时数据已观测,方法和事件已配置,但尚未挂载到页面。
- mounted:组件挂载到页面后调用,此时可以进行 DOM 操作。
- destroyed:组件被销毁前调用,用于清理资源,如取消定时器或移除事件监听。
生命周期触发顺序示例
-
首次打开首页
- 应用生命周期:
onLaunch
onShow
- 页面生命周期:
onLoad
onShow
onReady
- 组件生命周期(首次显示时加载组件):
beforeCreate
created
mounted
- 应用生命周期:
-
点击“显示/隐藏组件”按钮
- 显示组件时:
beforeCreate
created
mounted
- 隐藏组件时:
destroyed
- 显示组件时:
-
点击“打开新页面”按钮,使用
navigateTo
- 当前页面生命周期:
onHide
(首页被隐藏)
- 新页面生命周期:
onLoad
onShow
onReady
- 当前页面生命周期:
-
返回首页
- 新页面生命周期:
onHide
(新页面被隐藏)
- 首页生命周期:
onShow
- 新页面生命周期:
-
使用
redirectTo
打开新页面- 当前页面生命周期:
onUnload
(首页被卸载)
- 新页面生命周期:
onLoad
onShow
onReady
- 当前页面生命周期:
五、其他组件生命周期方法
除了常用的 beforeCreate
、created
、mounted
和 destroyed
,组件还提供了其他生命周期方法,如:
- beforeMount:在挂载开始之前调用,此时模板已编译但未挂载。
- beforeUpdate:数据更新之前调用,可以在此对数据进行处理。
- updated:数据更新后调用,此时 DOM 已更新。
- activated 和 deactivated:用于
<keep-alive>
缓存组件的激活与停用。
示例代码
components/AdvancedComponent.vue
<template> <view class="advanced-container"> <text>{{ advancedMessage }}</text> </view> </template> <script> export default { name: 'AdvancedComponent', data() { return { advancedMessage: '这是一个高级组件' } }, beforeCreate() { console.log('高级组件生命周期:beforeCreate'); }, created() { console.log('高级组件生命周期:created'); }, beforeMount() { console.log('高级组件生命周期:beforeMount'); }, mounted() { console.log('高级组件生命周期:mounted'); }, beforeUpdate() { console.log('高级组件生命周期:beforeUpdate'); }, updated() { console.log('高级组件生命周期:updated'); }, activated() { console.log('高级组件生命周期:activated'); }, deactivated() { console.log('高级组件生命周期:deactivated'); }, destroyed() { console.log('高级组件生命周期:destroyed'); } } </script> <style> .advanced-container { padding: 20rpx; background-color: #e0ffe0; border: 1px solid #00cc00; } </style>
解析
- beforeMount:在挂载开始之前调用,此时模板已编译但未挂载,可以进行一些预处理操作。
- beforeUpdate:数据更新之前调用,可以在此对数据进行进一步处理或验证。
- updated:数据更新后调用,此时 DOM 已更新,可以进行与 DOM 相关的操作。
- activated 和 deactivated:当使用
<keep-alive>
缓存组件时,activated
在组件被激活时调用,deactivated
在组件被停用时调用。
使用 <keep-alive>
缓存组件
pages/index/index.vue
<template> <view class="container"> <button @click="toggleComponent">显示/隐藏高级组件</button> <!-- 使用 <keep-alive> 缓存组件 --> <keep-alive> <AdvancedComponent v-if="showAdvancedComponent"></AdvancedComponent> </keep-alive> </view> </template> <script> import AdvancedComponent from '@/components/AdvancedComponent.vue' export default { components: { AdvancedComponent }, data() { return { showAdvancedComponent: false } }, methods: { toggleComponent() { this.showAdvancedComponent = !this.showAdvancedComponent; } } } </script> <style> .container { padding: 20rpx; } button { margin-bottom: 20rpx; } </style>
解析
- :包裹需要缓存的组件,激活和停用时触发
activated
和deactivated
。 - toggleComponent 方法用于控制高级组件的显示与隐藏,同时触发相应的生命周期方法。
六、注意事项
- 唯一性:应用生命周期方法只能在
App.vue
中定义,页面生命周期方法应在各自的页面.vue
文件中定义,组件生命周期方法仅在自定义组件中定义。 - 避免混淆:不要将应用生命周期方法和页面、组件生命周期方法混淆,确保在正确的位置定义相应的方法。
- 资源管理:在生命周期方法中合理管理资源,如在
destroyed
中清理定时器或事件监听,避免内存泄漏。 - 条件编译:在使用条件编译时,确保不同平台下生命周期方法的逻辑完整,避免因平台差异导致的问题。
七、作业与实践
作业
-
应用生命周期实践:
- 在
App.vue
的onLaunch
中初始化全局变量,如用户登录状态。 - 在
onShow
中检测应用从后台回到前台,刷新部分数据。
- 在
-
页面生命周期实践:
- 在首页的
onLoad
中请求初始数据。 - 在
onShow
中刷新页面数据,确保每次显示时数据是最新的。 - 使用
navigateTo
和redirectTo
打开新页面,观察生命周期方法的触发顺序。
- 在首页的
-
组件生命周期实践:
- 创建多个自定义组件,分别在不同生命周期方法中添加
console.log
语句,观察它们的触发顺序。 - 在组件的
mounted
中进行 DOM 操作,如修改元素样式,验证生命周期方法的执行时机。 - 在组件的
destroyed
中清理资源,如取消定时器或移除事件监听。
- 创建多个自定义组件,分别在不同生命周期方法中添加
-
高级组件生命周期应用:
- 创建一个使用
<keep-alive>
缓存的组件,利用activated
和deactivated
方法管理组件状态。 - 在
beforeUpdate
和updated
方法中处理数据变化,确保组件状态的一致性。
- 创建一个使用
实践建议
- 日志调试:在各个生命周期方法中添加
console.log
,帮助理解方法的触发时机和顺序,便于调试和优化。 - 合理利用生命周期方法:
beforeCreate
和created
:用于初始化数据和配置事件。mounted
:进行 DOM 操作或调用第三方库。beforeUpdate
和updated
:处理数据变化和更新视图。destroyed
:清理资源,防止内存泄漏。
- 组件复用:通过理解组件生命周期,设计高复用性的组件,提高代码的可维护性和效率。
- 资源管理:在组件销毁前,确保所有资源(如定时器、事件监听)都已正确释放,避免潜在的问题。
- 条件编译结合生命周期:在不同平台下执行不同的生命周期逻辑,确保应用的跨平台兼容性。
八、总结
通过本节课的学习,掌握了 Uni-App 中生命周期的基本概念和常用方法,包括:
- 应用生命周期:
onLaunch
、onShow
、onHide
、onError
、onUnhandledRejection
- 页面生命周期:
onLoad
、onReady
、onShow
、onHide
、onUnload
- 组件生命周期:
beforeCreate
、created
、beforeMount
、mounted
、beforeUpdate
、updated
、activated
、deactivated
、destroyed
理解并正确使用生命周期方法,能够帮助开发者在 Uni-App 应用中更好地管理数据、优化性能和提升用户体验。建议同学们通过作业和实际项目,进一步巩固和应用所学知识,为后续更复杂的开发任务打下坚实的基础。
参考资料: