uni-app:生命周期

生命周期概览图

应用启动
   ↓
[应用生命周期] 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 })

×

喜欢就点赞,疼爱就打赏