六维教程

uni-app 生命周期

生命周期指一个应用或页面从出生到销毁的过程中,各个节点自动触发的钩子函数。理解生命周期,才知道代码该往哪里放,比如请求数据应该放在哪个钩子里。

uni-app 的生命周期分两层,应用生命周期(整个应用级)和页面生命周期(单个页面级)。

应用生命周期

写在 App.vue 里,整个应用只触发一次:

<script>
export default {
  onLaunch() {
    console.log('应用初始化完成,全局只触发一次')
    // 适合做:检查登录态、读取全局配置、上报启动日志
  },
  onShow() {
    console.log('应用进入前台(从后台切回来也会触发)')
  },
  onHide() {
    console.log('应用进入后台(按 Home 键、切到别的 App)')
  }
}
</script>

三个钩子各管什么:

钩子 触发时机 典型用途
onLaunch 应用初始化完成,整个生命周期只触发一次 检查登录态、初始化全局数据
onShow 应用启动完成、或从后台切回前台 刷新全局数据、检查版本
onHide 应用切到后台 暂停播放、保存草稿

注意onLaunch 触发时页面还没创建,此时拿不到页面 DOM;想判断首次启动还是从后台回来,可以在 onLaunch 里记一个标志。

页面生命周期

写在每个页面<script> 里,页面从打开到关闭完整走一遍:

<script>
export default {
  data() {
    return { id: '' }
  },
  onLoad(options) {
    console.log('页面加载,可接收跳转参数', options)
  },
  onShow() {
    console.log('页面显示(每次显示都触发)')
  },
  onReady() {
    console.log('页面初次渲染完成,可以操作 DOM 了')
  },
  onHide() {
    console.log('页面被隐藏(跳转到别的页面时)')
  },
  onUnload() {
    console.log('页面卸载(关闭页面时)')
  }
}
</script>

触发顺序

钩子 触发时机 触发次数
onLoad 页面加载,带跳转参数 每次创建触发一次
onShow 页面显示 每次显示都触发
onReady 初次渲染完成 每次创建触发一次
onHide 页面被覆盖(跳走) 每次隐藏都触发
onUnload 页面销毁(返回关闭) 每次关闭触发一次

三个钩子的触发次数要记牢,onShowonHide每次都会触发,onLoadonReadyonUnload 只在创建或销毁时触发一次。

生命周期与路由跳转的关系

这是最容易搞混的点。用 navigateTo 跳到新页面时,旧页面不会销毁,只触发 onHide,返回时才触发 onUnload

打开详情页:
index(onHide) → detail(onLoad → onShow → onReady)

返回首页:
detail(onUnload) → index(onShow)

所以判断「页面是否重新显示」要用 onShow 而不是 onLoad。典型场景,列表页跳详情、详情页改完数据返回,列表页要在 onShow 里重新拉取数据,放 onLoad 里不会生效(页面没销毁,不会再走 onLoad)。

Vue3 的组合式写法

如果你用 <script setup>,生命周期钩子从 @dcloudio/uni-app 里引入,用法是传回调:

<script setup>
import { ref } from 'vue'
import { onLoad, onShow, onUnload } from '@dcloudio/uni-app'

const id = ref('')

onLoad((options) => {
  id.value = options.id || ''
})

onShow(() => {
  console.log('页面显示')
})

onUnload(() => {
  console.log('页面卸载')
})
</script>

高频附加钩子

页面生命周期还有几个高频附加钩子,虽然不在这条主链上,但列表页几乎必用:

<script>
export default {
  // 下拉刷新(需在 pages.json 开启 enablePullDownRefresh)
  onPullDownRefresh() {
    console.log('用户下拉刷新')
    // 拉完数据记得关闭动画
    uni.stopPullDownRefresh()
  },
  // 滚动到底部(上拉加载更多)
  onReachBottom() {
    console.log('滚到底了,加载下一页')
  },
  // 小程序分享
  onShareAppMessage() {
    return { title: '分享标题', path: '/pages/index/index' }
  }
}
</script>
钩子 触发时机 典型用途
onPullDownRefresh 用户下拉刷新 重新拉取列表数据
onReachBottom 滚动触底 分页加载下一页
onShareAppMessage 用户点分享 自定义分享标题和内容
onPageScroll 页面滚动 吸顶导航、返回顶部按钮

onPullDownRefresh 需要在 pages.json 的页面 style 里开启:

{
  "pages": [
    {
      "path": "pages/index/index",
      "style": {
        "enablePullDownRefresh": true
      }
    }
  ]
}

各平台差异提示

大部分钩子在所有平台行为一致,两个容易踩的差异:

  • onShow 在 H5 端,浏览器标签页切换回来时也会触发,如果 onShow 里有重逻辑要注意频率。
  • onHide 在小程序端,切到后台、跳转到另一个小程序或打开客服等都会触发,写清理逻辑时要考虑这些场景。

综合示例:完整流程演示

首页 → 详情页 → 返回,打印全部钩子看触发顺序:

首页 index.vue

<script>
export default {
  onLoad() {
    console.log('index onLoad')
  },
  onShow() {
    console.log('index onShow')
  },
  onReady() {
    console.log('index onReady')
  },
  onHide() {
    console.log('index onHide(被详情页覆盖)')
  },
  onUnload() {
    console.log('index onUnload(页面销毁)')
  },
  methods: {
    goDetail() {
      uni.navigateTo({ url: '/pages/detail/detail?id=1' })
    }
  }
}
</script>

<template>
  <button @click="goDetail">打开详情页</button>
</template>

详情页 detail.vue(只打 onLoad 和 onShow):

<script>
export default {
  onLoad(options) {
    console.log('detail onLoad,参数:', options)
  },
  onShow() {
    console.log('detail onShow')
  }
}
</script>

<template>
  <view>详情页</view>
</template>

控制台输出顺序:

[页面加载] index onLoad
[页面显示] index onShow
[渲染完成] index onReady
[点击跳转]
[覆盖隐藏] index onHide
[创建页面] detail onLoad,参数:{ id: '1' }
[页面显示] detail onShow
[点击返回]
[销毁页面] detail onUnload
[再次显示] index onShow

对照这张日志就能看出,onShow 每次显示都触发,onLoad 每个页面实例只触发一次,这决定了数据加载放哪。

总结

层级 钩子 常用场景
应用级 onLaunch / onShow / onHide 全局初始化、前后台切换
页面级 onLoad / onShow / onReady / onHide / onUnload 参数接收、数据加载
附加 onPullDownRefresh / onReachBottom / onShareAppMessage 刷新、分页、分享

一句话总结:页面级生命周期里,onLoad 只走一次用来接参数,onShow 每次显示都走用来刷新数据,onHide 是被盖住,onUnload 是销毁,列表页数据刷新记得放 onShow

上一篇
uni-app 条件编译
下一篇
uni-app 常用 API