生命周期概览图
应用启动
↓
[应用生命周期] onLaunch → onShow → onHide(应用进入后台)→ onUniNViewMessage(扩展)
↓
页面打开
↓
[页面生命周期] onLoad → onShow → onReady → onUnload(页面被关闭)
↓ ↓
onPullDownRefresh(下拉刷新)
onReachBottom(触底加载)
onPageScroll(页面滚动)
onShareAppMessage(分享)
onBackPress(返回按钮)
onNavigationBarButtonTap(导航栏按钮)
↓
[组件生命周期] setup → onMounted → onUpdated → onUnmounted
应用生命周期(整个APP级别)
在 App.vue 中定义,控制整个应用的状态:
// App.vue
<script setup>
// 应用生命周期钩子
onLaunch((options) => {
// 1. 初始化完成时触发(全局只执行一次)
console.log('App Launch - 应用初始化', options)
// 使用场景:检查登录状态、获取全局配置、初始化数据
checkLoginStatus()
loadGlobalConfig()
})
onShow((options) => {
// 2. 应用启动或从后台进入前台时触发
console.log('App Show - 应用显示', options)
// 使用场景:刷新数据、恢复定时器、统计埋点
refreshData()
resumeTimer()
})
onHide(() => {
// 3. 应用从前台进入后台时触发
console.log('App Hide - 应用隐藏')
// 使用场景:暂停操作、保存草稿、清理定时器
pauseTasks()
saveDraft()
})
onError((error) => {
// 4. 应用发生错误时触发
console.log('App Error - 应用错误', error)
// 使用场景:错误上报、降级处理
reportError(error)
})
onUnhandledRejection(({ reason, promise }) => {
// 5. Promise 拒绝未被捕获时触发
console.log('Unhandled Rejection', reason)
})
onPageNotFound((options) => {
// 6. 页面不存在时触发
console.log('Page Not Found', options)
// 重定向到404页面
uni.redirectTo({
url: '/pages/404/404'
})
})
onThemeChange(({ theme }) => {
// 7. 系统主题变化时触发(仅支持暗黑模式)
console.log('Theme Change', theme)
})
</script>
页面生命周期(单个页面级别)
基础生命周期
// pages/index/index.vue
<script setup>
import { ref } from 'vue'
import {
onLoad, onShow, onReady,
onHide, onUnload
} from '@dcloudio/uni-app'
// ① 页面加载(只执行一次)
onLoad((options) => {
console.log('1. Page onLoad - 页面加载')
// ✅ 适用:接收参数、初始化数据、请求初始数据
const { id, type } = options
pageId.value = id
loadInitData()
})
// ② 页面显示(每次进入页面都执行)
onShow(() => {
console.log('2. Page onShow - 页面显示')
// ✅ 适用:刷新数据、恢复状态、统计埋点
refreshPageData()
resumePlayer()
})
// ③ 页面首次渲染完成(只执行一次)
onReady(() => {
console.log('3. Page onReady - 页面准备就绪')
// ✅ 适用:操作DOM、获取节点信息、初始化地图
getElementInfo()
initMap()
})
// ④ 页面隐藏(当页面被覆盖)
onHide(() => {
console.log('4. Page onHide - 页面隐藏')
// ✅ 适用:暂停操作、保存草稿、暂停视频
pauseVideo()
saveFormData()
})
// ⑤ 页面卸载(页面被销毁)
onUnload(() => {
console.log('5. Page onUnload - 页面卸载')
// ✅ 适用:清理定时器、取消订阅、释放资源
clearTimer()
unsubscribe()
})
</script>
onLoad VS onShow 和 onUnload VS onHide
| 生命周期 | 触发条件 | 技术本质 |
|---|---|---|
| onLoad | 入栈时 | 页面实例被创建,推入页面栈 |
| onShow | 在栈顶时 | 页面成为当前可见页面 |
| onHide | 离开栈顶时 | 页面被其他页面覆盖 |
| onUnload | 出栈时 | 页面实例被销毁,移出页面栈 |
// 初始状态:空栈
栈:[]
// 1. 打开首页
栈:[首页]
// 首页 onLoad(入栈时)
// 首页 onShow(成为栈顶)
// 2. 从首页跳转到列表页
栈:[首页, 列表页]
// 列表页 onLoad(入栈时)
// 首页 onHide(不再是栈顶)
// 列表页 onShow(成为栈顶)
// 3. 从列表页跳转到详情页
栈:[首页, 列表页, 详情页]
// 详情页 onLoad(入栈时)
// 列表页 onHide(不再是栈顶)
// 详情页 onShow(成为栈顶)
// 4. 从详情页返回列表页
栈:[首页, 列表页]
// 详情页 onUnload(出栈,被销毁)
// 列表页 onShow(重新成为栈顶)
// 5. 从列表页返回首页
栈:[首页]
// 列表页 onUnload(出栈,被销毁)
// 首页 onShow(重新成为栈顶)
onLoad
onLoad((options) => {
// options: 包含所有URL查询参数的对象
console.log(options) // { key1: value1, key2: value2, ... }
})
// onLoad 只能接收 URL 参数,不能接收其他方式传递的参数。
// 页面A
uni.navigateTo({
url: '/pages/detail/detail?id=100&type=1'
})
// 页面B - onLoad 能接收到
onLoad((options) => {
console.log(options) // { id: "100", type: "1" }
})
页面事件处理函数
<script setup>
import {
onPullDownRefresh, // 下拉刷新
onReachBottom, // 触底加载
onPageScroll, // 页面滚动
onShareAppMessage, // 分享
onShareTimeline, // 分享到朋友圈(微信小程序)
onAddToFavorites, // 收藏
onBackPress, // 返回按钮
onNavigationBarButtonTap, // 导航栏按钮点击
onTabItemTap, // tab 点击(仅tabBar页面)
onResize // 窗口尺寸变化
} from '@dcloudio/uni-app'
// 下拉刷新
onPullDownRefresh(() => {
console.log('下拉刷新')
// 刷新数据
refreshData().finally(() => {
// 关闭下拉刷新动画
uni.stopPullDownRefresh()
})
})
// 触底加载
onReachBottom(() => {
console.log('触底加载更多')
// 加载下一页数据
if (hasMore.value) {
loadMoreData()
}
})
// 页面滚动
onPageScroll(({ scrollTop }) => {
console.log('滚动位置:', scrollTop)
// 根据滚动距离改变UI
showBackToTop.value = scrollTop > 500
})
// 分享给朋友
onShareAppMessage((options) => {
console.log('分享', options)
return {
title: '分享标题',
path: '/pages/index/index',
imageUrl: '/static/share.png'
}
})
// 分享到朋友圈
onShareTimeline(() => {
return {
title: '分享标题',
query: 'id=123',
imageUrl: '/static/share.png'
}
})
// 收藏
onAddToFavorites((options) => {
return {
title: '收藏标题',
query: 'id=123',
imageUrl: '/static/fav.png'
}
})
// 返回按钮
onBackPress((options) => {
console.log('返回按钮点击', options)
// 返回 true 阻止默认返回行为
if (hasUnsavedData.value) {
showSaveConfirm()
return true
}
return false
})
// 导航栏按钮点击
onNavigationBarButtonTap(({ index, text }) => {
console.log('导航栏按钮点击', index, text)
if (index === 0) {
// 第一个按钮
openShare()
}
})
// tab 点击(仅tabBar页面)
onTabItemTap(({ index, pagePath, text }) => {
console.log('tab点击', index, pagePath, text)
})
// 窗口尺寸变化(如横竖屏切换)
onResize(({ size }) => {
console.log('窗口尺寸变化', size.windowWidth, size.windowHeight)
})
</script>
组件生命周期(Vue 3 组合式API)
// components/MyComponent.vue
<script setup>
import {
ref, onMounted, onUpdated,
onUnmounted, onBeforeMount,
onBeforeUpdate, onBeforeUnmount,
onActivated, onDeactivated // keep-alive 专用
} from 'vue'
// 1. 挂载前
onBeforeMount(() => {
console.log('组件挂载前')
})
// 2. 挂载后
onMounted(() => {
console.log('组件挂载完成')
// ✅ 适用:DOM操作、事件监听、请求数据
initComponent()
})
// 3. 更新前
onBeforeUpdate(() => {
console.log('组件更新前')
})
// 4. 更新后
onUpdated(() => {
console.log('组件更新完成')
})
// 5. 卸载前
onBeforeUnmount(() => {
console.log('组件卸载前')
})
// 6. 卸载后
onUnmounted(() => {
console.log('组件卸载完成')
// ✅ 适用:清理定时器、取消事件监听
cleanup()
})
// 7. 被 keep-alive 缓存激活
onActivated(() => {
console.log('组件被激活')
})
// 8. 被 keep-alive 缓存停用
onDeactivated(() => {
console.log('组件被停用')
})
</script>
六、生命周期使用最佳实践
1. 数据请求的最佳位置
// ✅ 正确:根据需求选择合适的生命周期
onLoad(() => {
// 静态数据:页面加载时请求一次
loadStaticData()
})
onShow(() => {
// 动态数据:每次显示都刷新
refreshDynamicData()
})
// ❌ 错误:不要在 onReady 请求数据
onReady(() => {
// onReady 应该处理DOM操作,不是数据请求
})
2. 清理资源的最佳位置
// ✅ 正确:在对应生命周期清理
onMounted(() => {
timer = setInterval(() => {}, 1000)
})
onUnmounted(() => {
clearInterval(timer) // 组件卸载时清理
})
onHide(() => {
pauseVideo() // 页面隐藏时暂停
})
onShow(() => {
resumeVideo() // 页面显示时恢复
})
3. 参数传递处理
onLoad((options) => {
// 1. 解构参数
const { id, type, from } = options
// 2. 参数校验
if (!id) {
// 参数错误处理
uni.showToast({ title: '参数错误' })
return
}
// 3. 类型转换
const pageId = Number(id)
const pageType = type || 'default'
// 4. 初始化
initPage(pageId, pageType)
})
七、常见面试题
Q1: onLoad 和 onShow 的区别?
A:
onLoad:页面加载时执行一次,适合接收参数、初始化数据onShow:每次页面显示都执行,适合刷新数据、恢复状态
Q2: onReady 和 onMounted 的区别?
A:
onReady:页面级别,整个页面渲染完成onMounted:组件级别,单个组件挂载完成
Q3: 页面返回时如何传递数据?
A: 使用事件总线或全局状态管理
// 方式1:事件总线
uni.$emit('dataUpdate', { id: 123 })
// 方式2:getCurrentPages
const pages = getCurrentPages()
const prevPage = pages[pages.length - 2]
prevPage.$vm.setData({ refreshed: true })