uni-app 生命週期詳解
本文將詳細介紹 uni-app 的生命週期,包括應用生命週期、頁面生命週期和元件生命週期,幫助您更好地理解和使用 uni-app。
概述
生命週期是指應用程式從建立到銷燬的整個過程中,特定時間點觸發的函數,開發者可以在這些函數中執行自己的程式碼邏輯。
uni-app 生命週期分類
| 型別 | 說明 | 監聽位置 |
|---|---|---|
| 應用生命週期 | 應用級別的生命週期函數 | App.vue 中監聽 |
| 頁面生命週期 | 頁面級別的生命週期函數 | 頁面中監聽 |
| 元件生命週期 | 元件級別的生命週期函數 | 元件中監聽 |
應用生命週期
應用生命週期是指 uni-app 從啟動到解除安裝的過程中,特定時間點觸發的函數。這些函數在 App.vue 中定義。
生命週期函數
| 函數名 | 說明 | 引數 | 適用場景 |
|---|---|---|---|
onLaunch | 應用初始化完成時觸發(全域只觸發一次) | options(啟動引數) | 初始化應用資料、檢查更新、獲取使用者資訊 |
onShow | 應用啟動或從後臺進入前臺時觸發 | options(啟動引數) | 恢復應用狀態、重新整理資料、統計使用時長 |
onHide | 應用從前臺進入後臺時觸發 | - | 暫停音視訊播放、儲存應用狀態、暫停定時器 |
onError | 應用執行報錯時觸發 | err(錯誤資訊) | 錯誤日誌收集、異常上報 |
onUniNViewMessage | 監聽 nvue 頁面傳送的資料 | event(訊息物件) | 接收 nvue 頁面傳送的訊息 |
應用生命週期示例
vue
<script>
export default {
onLaunch: function(options) {
console.log('App Launch')
console.log('啟動引數:', options)
// 初始化應用資料
this.checkUpdate()
this.getUserInfo()
},
onShow: function(options) {
console.log('App Show')
console.log('顯示引數:', options)
// 恢復應用狀態
this.resumeAudio()
this.refreshData()
},
onHide: function() {
console.log('App Hide')
// 儲存應用狀態
this.saveAppState()
this.pauseAudio()
},
onError: function(err) {
console.error('App Error:', err)
// 錯誤上報
this.reportError(err)
},
methods: {
checkUpdate() {
// 檢查應用更新
uni.getUpdateManager().onCheckForUpdate((res) => {
if (res.hasUpdate) {
console.log('發現新版本')
}
})
},
getUserInfo() {
// 獲取使用者資訊
uni.getStorage({
key: 'userInfo',
success: (res) => {
this.userInfo = res.data
}
})
},
resumeAudio() {
// 恢復音訊播放
if (this.audioContext) {
this.audioContext.play()
}
},
pauseAudio() {
// 暫停音訊播放
if (this.audioContext) {
this.audioContext.pause()
}
},
refreshData() {
// 重新整理資料
this.$store.dispatch('refreshData')
},
saveAppState() {
// 儲存應用狀態
uni.setStorage({
key: 'appState',
data: this.appState
})
},
reportError(err) {
// 錯誤上報
uni.request({
url: 'https://api.example.com/error/report',
method: 'POST',
data: {
error: err,
timestamp: Date.now()
}
})
}
}
}
</script>啟動引數說明
不同平台的啟動引數有所不同:
小程式平台
javascript
onLaunch: function(options) {
// 微信小程式
console.log('場景值:', options.scene)
console.log('路徑:', options.path)
console.log('查詢引數:', options.query)
// 支付寶小程式
console.log('啟動引數:', options.query)
}App平台
javascript
onLaunch: function(options) {
// App平台
console.log('啟動來源:', options.referrerInfo)
console.log('啟動引數:', options.query)
}頁面生命週期
頁面生命週期是指頁面從載入到銷燬的過程中,特定時間點觸發的函數。這些函數在頁面元件中定義。
生命週期函數
| 函數名 | 說明 | 引數 | 觸發時機 |
|---|---|---|---|
onLoad | 頁面載入時觸發 | options(頁面引數) | 頁面初次載入時 |
onShow | 頁面顯示時觸發 | - | 頁面顯示或從後臺進入前臺時 |
onReady | 頁面初次渲染完成時觸發 | - | 頁面初次渲染完成時 |
onHide | 頁面隱藏時觸發 | - | 頁面隱藏或進入後臺時 |
onUnload | 頁面解除安裝時觸發 | - | 頁面路由跳轉離開時 |
onPullDownRefresh | 使用者下拉重新整理時觸發 | - | 下拉重新整理操作時 |
onReachBottom | 頁面滾動到底部時觸發 | - | 頁面滾動到底部時 |
onShareAppMessage | 使用者點選分享時觸發 | - | 點選分享按鈕時 |
onPageScroll | 頁面滾動時觸發 | Object(滾動位置) | 頁面滾動時 |
onResize | 頁面尺寸變化時觸發 | Object(尺寸資訊) | 頁面尺寸變化時 |
onTabItemTap | 點選 tab 時觸發 | Object(tab資訊) | 點選底部 tab 時 |
頁面生命週期示例
vue
<template>
<view class="page">
<text>{{ title }}</text>
<button @click="handleClick">點選我</button>
</view>
</template>
<script>
export default {
data() {
return {
title: '頁面標題',
pageData: null
}
},
onLoad(options) {
console.log('頁面載入', options)
// 獲取頁面引數
this.pageId = options.id
// 載入頁面資料
this.loadPageData()
},
onShow() {
console.log('頁面顯示')
// 恢復頁面狀態
this.resumePage()
},
onReady() {
console.log('頁面渲染完成')
// 執行頁面初始化操作
this.initPage()
},
onHide() {
console.log('頁面隱藏')
// 儲存頁面狀態
this.savePageState()
},
onUnload() {
console.log('頁面解除安裝')
// 清理資源
this.cleanup()
},
onPullDownRefresh() {
console.log('下拉重新整理')
// 重新整理資料
this.refreshData().then(() => {
// 停止下拉重新整理
uni.stopPullDownRefresh()
})
},
onReachBottom() {
console.log('滾動到底部')
// 載入更多資料
this.loadMoreData()
},
onShareAppMessage() {
return {
title: '分享標題',
path: '/pages/index/index',
imageUrl: '/static/share.jpg'
}
},
onPageScroll(e) {
// 頁面滾動事件
this.scrollTop = e.scrollTop
},
onTabItemTap(e) {
console.log('點選tab', e)
},
methods: {
loadPageData() {
// 載入頁面資料
uni.request({
url: `/api/page/${this.pageId}`,
success: (res) => {
this.pageData = res.data
}
})
},
resumePage() {
// 恢復頁面狀態
if (this.audioPlaying) {
this.resumeAudio()
}
},
initPage() {
// 頁面初始化
this.setupEventListeners()
this.loadEssentialData()
},
savePageState() {
// 儲存頁面狀態
uni.setStorage({
key: `pageState_${this.pageId}`,
data: this.pageState
})
},
cleanup() {
// 清理資源
this.removeEventListeners()
this.clearTimers()
},
refreshData() {
// 重新整理資料
return new Promise((resolve) => {
uni.request({
url: `/api/page/${this.pageId}/refresh`,
success: (res) => {
this.pageData = res.data
resolve()
}
})
})
},
loadMoreData() {
// 載入更多資料
if (!this.loading && this.hasMore) {
this.loading = true
uni.request({
url: `/api/page/${this.pageId}/more`,
data: { page: this.currentPage + 1 },
success: (res) => {
this.pageData = this.pageData.concat(res.data)
this.currentPage++
this.loading = false
}
})
}
}
}
}
</script>頁面引數處理
javascript
onLoad(options) {
// 處理頁面引數
this.id = options.id || ''
this.type = options.type || 'default'
this.from = options.from || ''
// 驗證必填引數
if (!this.id) {
uni.showToast({
title: '缺少必要引數',
icon: 'error'
})
uni.navigateBack()
return
}
// 根據引數載入不同資料
this.loadDataByType(this.type)
}元件生命週期
元件生命週期是指 Vue 元件從建立到銷燬的過程中,特定時間點觸發的函數。這些函數遵循 Vue 3 的生命週期規範。
生命週期函數
| 函數名 | 說明 | 觸發時機 |
|---|---|---|
beforeCreate | 例項初始化之後,資料觀測之前 | 元件建立前 |
created | 例項建立完成後 | 元件建立完成後 |
beforeMount | 掛載開始之前被呼叫 | 掛載到DOM前 |
mounted | 例項掛載完成後被呼叫 | 掛載到DOM後 |
beforeUpdate | 資料更新時呼叫,發生在虛擬DOM重新渲染之前 | 資料更新前 |
updated | 由於資料更改導致的虛擬DOM重新渲染完成後 | 資料更新後 |
beforeUnmount | 例項銷燬之前呼叫 | 元件銷燬前 |
unmounted | 例項銷燬後呼叫 | 元件銷燬後 |
activated | 被 keep-alive 快取的元件啟用時呼叫 | 快取元件啟用時 |
deactivated | 被 keep-alive 快取的元件停用時呼叫 | 快取元件停用時 |
errorCaptured | 捕獲子元件錯誤時呼叫 | 子元件錯誤時 |
元件生命週期示例
vue
<template>
<view class="component">
<text>{{ message }}</text>
<button @click="updateMessage">更新訊息</button>
</view>
</template>
<script>
export default {
name: 'MyComponent',
props: {
initialMessage: {
type: String,
default: 'Hello'
}
},
data() {
return {
message: '',
timer: null,
count: 0
}
},
beforeCreate() {
console.log('元件建立前')
// 此時還不能訪問 data 和 methods
},
created() {
console.log('元件建立完成')
// 可以訪問 data 和 methods,但還不能訪問 DOM
this.message = this.initialMessage
this.setupTimer()
},
beforeMount() {
console.log('掛載前')
// 模板編譯完成,但還未掛載到DOM
},
mounted() {
console.log('掛載完成')
// 元件已掛載到DOM,可以訪問DOM元素
this.$nextTick(() => {
console.log('DOM更新完成')
})
},
beforeUpdate() {
console.log('更新前')
// 資料即將更新,DOM還未重新渲染
},
updated() {
console.log('更新完成')
// 資料更新完成,DOM已重新渲染
},
beforeUnmount() {
console.log('解除安裝前')
// 元件即將銷燬,清理資源
this.cleanup()
},
unmounted() {
console.log('解除安裝完成')
// 元件已銷燬
},
activated() {
console.log('元件啟用')
// 被 keep-alive 快取的元件啟用時
this.resumeTimer()
},
deactivated() {
console.log('元件停用')
// 被 keep-alive 快取的元件停用時
this.pauseTimer()
},
errorCaptured(err, instance, info) {
console.error('捕獲到錯誤:', err)
// 可以在此處理錯誤或上報
this.reportError(err, info)
// 返回 false 阻止錯誤繼續向上傳播
return false
},
methods: {
updateMessage() {
this.message = `更新後的訊息 ${Date.now()}`
this.count++
},
setupTimer() {
this.timer = setInterval(() => {
console.log('定時器執行')
}, 1000)
},
cleanup() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
},
resumeTimer() {
if (!this.timer) {
this.setupTimer()
}
},
pauseTimer() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
},
reportError(err, info) {
// 錯誤上報
console.error('元件錯誤:', err, info)
}
}
}
</script>生命週期執行順序
頁面載入時
- 應用生命週期:
onLaunch→onShow - 頁面生命週期:
onLoad→onShow→onReady - 元件生命週期:
beforeCreate→created→beforeMount→mounted
頁面切換時
從頁面A切換到頁面B
- 頁面A:
onHide - 頁面B:
onLoad→onShow→onReady - 頁面A:
onUnload(如果不再返回)
返回頁面A
- 頁面B:
onHide - 頁面A:
onShow
應用狀態變化
應用進入後臺
- 當前頁面:
onHide - 應用:
onHide
應用返回前臺
- 應用:
onShow - 當前頁面:
onShow
最佳實踐
1. 合理使用生命週期
- onLoad:用於初始化頁面資料
- onShow:用於恢復頁面狀態
- onReady:用於執行DOM相關操作
- onHide/onUnload:用於清理資源
2. 效能優化
- 避免在生命週期中執行耗時操作
- 使用非同步操作避免阻塞渲染
- 合理使用快取減少重複載入
- 及時清理定時器和事件監聽器
3. 錯誤處理
- 在
onError中處理應用級錯誤 - 在
errorCaptured中處理元件錯誤 - 使用 try-catch 捕獲同步錯誤
- 合理處理非同步操作的錯誤
4. 狀態管理
- 在合適的生命週期中儲存和恢復狀態
- 使用 Vuex 管理全域狀態
- 使用本地儲存持久化重要資料
- 合理處理頁面間狀態傳遞
常見問題
Q: onLoad 和 created 有什麼區別?
A: onLoad 是 uni-app 頁面特有的生命週期,用於接收頁面引數;created 是 Vue 元件的生命週期,用於元件初始化。在頁面中,通常使用 onLoad 處理頁面引數。
Q: 如何在不同生命週期中傳遞資料?
A: 可以使用以下方式:
- 頁面引數:透過路由傳遞
- 全域狀態:使用 Vuex
- 本地儲存:使用 uni.setStorage
- 事件匯流排:使用 mitt 或自定義事件
Q: 生命週期函數可以是非同步的嗎?
A: 可以,但需要注意:
- 非同步操作不會阻塞生命週期執行
- 需要處理非同步操作的錯誤
- 避免在生命週期中執行過於耗時的非同步操作
Q: 如何除錯生命週期執行順序?
A: 可以在各個生命週期函數中新增日誌輸出,觀察執行順序:
javascript
onLoad() {
console.log('onLoad')
}
onShow() {
console.log('onShow')
}
mounted() {
console.log('mounted')
}掌握生命週期是高效開發uni-app應用的關鍵,希望本文對您有所幫助!