You've already forked Pandona-Engine
564 lines
11 KiB
Markdown
564 lines
11 KiB
Markdown
# 生命周期
|
||
|
||
PE引擎为场景提供了完整的生命周期钩子,让你能够在适当的时机执行初始化、清理和其他操作。理解生命周期对于开发高效、稳定的PE应用至关重要。
|
||
|
||
## 生命周期钩子概览
|
||
|
||
每个PE场景都有四个主要的生命周期钩子:
|
||
|
||
1. **onLoad** - 场景加载时调用(只执行一次)
|
||
2. **onShow** - 场景显示时调用(每次显示都会执行)
|
||
3. **onHide** - 场景隐藏时调用
|
||
4. **onDestory** - 场景销毁时调用(只执行一次)
|
||
|
||
## onLoad
|
||
|
||
`onLoad`钩子在场景首次加载时调用,只执行一次。这是进行一次性初始化操作的最佳时机。
|
||
|
||
```html
|
||
<sence>
|
||
<box class="welcome">欢迎来到PE引擎</box>
|
||
</sence>
|
||
|
||
<script>
|
||
// 在onLoad中进行一次性初始化
|
||
onLoad(() => {
|
||
console.log('场景加载完成')
|
||
|
||
// 初始化数据
|
||
initializeData()
|
||
|
||
// 设置初始状态
|
||
setupInitialState()
|
||
|
||
// 加载资源
|
||
loadResources()
|
||
|
||
// 添加全局事件监听器
|
||
document.addEventListener('keydown', handleGlobalKeyDown)
|
||
})
|
||
|
||
function initializeData() {
|
||
// 初始化应用数据
|
||
console.log('初始化数据')
|
||
}
|
||
|
||
function setupInitialState() {
|
||
// 设置初始状态
|
||
console.log('设置初始状态')
|
||
}
|
||
|
||
function loadResources() {
|
||
// 加载必要的资源
|
||
console.log('加载资源')
|
||
}
|
||
|
||
function handleGlobalKeyDown(event) {
|
||
// 处理全局键盘事件
|
||
if (event.key === 'Escape') {
|
||
PE.navigateTo('/')
|
||
}
|
||
}
|
||
</script>
|
||
```
|
||
|
||
## onShow
|
||
|
||
`onShow`钩子在场景每次显示时调用。无论是首次显示还是从其他场景切换回来,都会执行此钩子。
|
||
|
||
```html
|
||
<sence>
|
||
<box class="content">场景内容</box>
|
||
<text class="last-updated">最后更新: {{ lastUpdated }}</text>
|
||
</sence>
|
||
|
||
<script>
|
||
let lastUpdated = ''
|
||
|
||
onShow(() => {
|
||
console.log('场景显示')
|
||
|
||
// 更新时间戳
|
||
updateTimestamp()
|
||
|
||
// 刷新数据
|
||
refreshData()
|
||
|
||
// 启动动画
|
||
startAnimations()
|
||
|
||
// 恢复定时器
|
||
resumeTimers()
|
||
})
|
||
|
||
function updateTimestamp() {
|
||
lastUpdated = new Date().toLocaleString()
|
||
const timeElement = game.getSceneElement('last-updated')
|
||
if (timeElement) {
|
||
timeElement.element.textContent = `最后更新: ${lastUpdated}`
|
||
}
|
||
}
|
||
|
||
function refreshData() {
|
||
// 刷新场景数据
|
||
console.log('刷新数据')
|
||
}
|
||
|
||
function startAnimations() {
|
||
// 启动场景动画
|
||
console.log('启动动画')
|
||
}
|
||
|
||
function resumeTimers() {
|
||
// 恢复定时器
|
||
console.log('恢复定时器')
|
||
}
|
||
</script>
|
||
```
|
||
|
||
## onHide
|
||
|
||
`onHide`钩子在场景隐藏时调用,比如切换到其他场景时。
|
||
|
||
```html
|
||
<sence>
|
||
<box class="content">场景内容</box>
|
||
</sence>
|
||
|
||
<script>
|
||
onHide(() => {
|
||
console.log('场景隐藏')
|
||
|
||
// 暂停动画
|
||
pauseAnimations()
|
||
|
||
// 暂停定时器
|
||
pauseTimers()
|
||
|
||
// 保存状态
|
||
saveState()
|
||
})
|
||
|
||
function pauseAnimations() {
|
||
// 暂停场景动画
|
||
console.log('暂停动画')
|
||
}
|
||
|
||
function pauseTimers() {
|
||
// 暂停定时器
|
||
console.log('暂停定时器')
|
||
}
|
||
|
||
function saveState() {
|
||
// 保存场景状态
|
||
console.log('保存状态')
|
||
}
|
||
</script>
|
||
```
|
||
|
||
## onDestory
|
||
|
||
`onDestory`钩子在场景销毁时调用,通常发生在应用关闭或场景被永久移除时。
|
||
|
||
```html
|
||
<sence>
|
||
<box class="content">场景内容</box>
|
||
</sence>
|
||
|
||
<script>
|
||
onDestory(() => {
|
||
console.log('场景销毁')
|
||
|
||
// 清理资源
|
||
cleanupResources()
|
||
|
||
// 移除事件监听器
|
||
removeEventListeners()
|
||
|
||
// 停止所有动画
|
||
stopAllAnimations()
|
||
|
||
// 清理定时器
|
||
clearAllTimers()
|
||
})
|
||
|
||
function cleanupResources() {
|
||
// 清理加载的资源
|
||
console.log('清理资源')
|
||
}
|
||
|
||
function removeEventListeners() {
|
||
// 移除添加的事件监听器
|
||
document.removeEventListener('keydown', handleGlobalKeyDown)
|
||
console.log('移除事件监听器')
|
||
}
|
||
|
||
function stopAllAnimations() {
|
||
// 停止所有动画
|
||
console.log('停止所有动画')
|
||
}
|
||
|
||
function clearAllTimers() {
|
||
// 清理所有定时器
|
||
console.log('清理定时器')
|
||
}
|
||
</script>
|
||
```
|
||
|
||
## 生命周期执行顺序
|
||
|
||
理解生命周期钩子的执行顺序对于正确管理场景状态非常重要:
|
||
|
||
### 首次加载场景
|
||
|
||
1. `onLoad` - 场景加载时执行(一次)
|
||
2. `onShow` - 场景显示时执行
|
||
|
||
### 切换到其他场景
|
||
|
||
1. 当前场景: `onHide` - 场景隐藏时执行
|
||
|
||
### 切换回场景
|
||
|
||
1. `onShow` - 场景显示时执行
|
||
|
||
### 销毁场景
|
||
|
||
1. `onHide` - 场景隐藏时执行(如果当前显示)
|
||
2. `onDestory` - 场景销毁时执行(一次)
|
||
|
||
## 实际应用示例
|
||
|
||
以下是一个完整的生命周期应用示例:
|
||
|
||
### scenes/dashboard/index.pe
|
||
|
||
```html
|
||
<sence>
|
||
<box class="dashboard">
|
||
<text class="title">仪表板</text>
|
||
<text class="status">状态: {{ status }}</text>
|
||
<text class="last-update">最后更新: {{ lastUpdate }}</text>
|
||
|
||
<box class="data-container">
|
||
<box for="{item} in dataItems" class="data-card">
|
||
<text class="card-title">{{ item.title }}</text>
|
||
<text class="card-value">{{ item.value }}</text>
|
||
</box>
|
||
</box>
|
||
|
||
<box class="controls">
|
||
<box class="btn btn-primary" @click="refreshData">刷新数据</box>
|
||
<box class="btn btn-secondary" @click="PE.navigateTo('/settings')">设置</box>
|
||
</box>
|
||
</box>
|
||
</sence>
|
||
|
||
<script>
|
||
// 数据状态
|
||
let status = '加载中...'
|
||
let lastUpdate = ''
|
||
let dataItems = []
|
||
let refreshTimer = null
|
||
let dataRefreshInterval = null
|
||
|
||
// onLoad - 只执行一次
|
||
onLoad(() => {
|
||
console.log('仪表板加载')
|
||
|
||
// 初始化数据
|
||
initializeData()
|
||
|
||
// 设置全局事件监听器
|
||
setupEventListeners()
|
||
|
||
// 加载初始数据
|
||
loadData()
|
||
})
|
||
|
||
// onShow - 每次显示时执行
|
||
onShow(() => {
|
||
console.log('仪表板显示')
|
||
|
||
// 更新状态
|
||
updateStatus('运行中')
|
||
|
||
// 启动定时刷新
|
||
startAutoRefresh()
|
||
|
||
// 恢复动画
|
||
resumeAnimations()
|
||
})
|
||
|
||
// onHide - 隐藏时执行
|
||
onHide(() => {
|
||
console.log('仪表板隐藏')
|
||
|
||
// 暂停自动刷新
|
||
stopAutoRefresh()
|
||
|
||
// 暂停动画
|
||
pauseAnimations()
|
||
|
||
// 保存当前状态
|
||
saveCurrentState()
|
||
})
|
||
|
||
// onDestory - 销毁时执行
|
||
onDestory(() => {
|
||
console.log('仪表板销毁')
|
||
|
||
// 清理所有资源
|
||
cleanup()
|
||
})
|
||
|
||
// 初始化数据
|
||
function initializeData() {
|
||
dataItems = [
|
||
{ title: '用户数', value: '0' },
|
||
{ title: '订单数', value: '0' },
|
||
{ title: '收入', value: '¥0' }
|
||
]
|
||
|
||
updateUI()
|
||
}
|
||
|
||
// 设置事件监听器
|
||
function setupEventListeners() {
|
||
// 监听网络状态变化
|
||
window.addEventListener('online', handleOnline)
|
||
window.addEventListener('offline', handleOffline)
|
||
}
|
||
|
||
// 加载数据
|
||
async function loadData() {
|
||
try {
|
||
updateStatus('加载数据中...')
|
||
|
||
// 模拟API调用
|
||
const data = await fetchDataFromAPI()
|
||
|
||
dataItems = data
|
||
lastUpdate = new Date().toLocaleString()
|
||
|
||
updateStatus('数据加载完成')
|
||
updateUI()
|
||
} catch (error) {
|
||
console.error('加载数据失败:', error)
|
||
updateStatus('数据加载失败')
|
||
}
|
||
}
|
||
|
||
// 模拟API调用
|
||
function fetchDataFromAPI() {
|
||
return new Promise((resolve) => {
|
||
setTimeout(() => {
|
||
resolve([
|
||
{ title: '用户数', value: Math.floor(Math.random() * 1000) },
|
||
{ title: '订单数', value: Math.floor(Math.random() * 500) },
|
||
{ title: '收入', value: '¥' + (Math.random() * 10000).toFixed(2) }
|
||
])
|
||
}, 1000)
|
||
})
|
||
}
|
||
|
||
// 启动自动刷新
|
||
function startAutoRefresh() {
|
||
if (dataRefreshInterval) {
|
||
clearInterval(dataRefreshInterval)
|
||
}
|
||
|
||
dataRefreshInterval = setInterval(() => {
|
||
loadData()
|
||
}, 30000) // 每30秒刷新一次
|
||
|
||
// 启动更新时间戳定时器
|
||
if (refreshTimer) {
|
||
clearInterval(refreshTimer)
|
||
}
|
||
|
||
refreshTimer = setInterval(() => {
|
||
updateTimestamp()
|
||
}, 1000)
|
||
}
|
||
|
||
// 停止自动刷新
|
||
function stopAutoRefresh() {
|
||
if (dataRefreshInterval) {
|
||
clearInterval(dataRefreshInterval)
|
||
dataRefreshInterval = null
|
||
}
|
||
|
||
if (refreshTimer) {
|
||
clearInterval(refreshTimer)
|
||
refreshTimer = null
|
||
}
|
||
}
|
||
|
||
// 更新状态显示
|
||
function updateStatus(newStatus) {
|
||
status = newStatus
|
||
const statusElement = game.getSceneElement('status')
|
||
if (statusElement) {
|
||
statusElement.element.textContent = `状态: ${status}`
|
||
}
|
||
}
|
||
|
||
// 更新时间戳显示
|
||
function updateTimestamp() {
|
||
if (lastUpdate) {
|
||
const timeElement = game.getSceneElement('last-update')
|
||
if (timeElement) {
|
||
const elapsed = Math.floor((new Date() - new Date(lastUpdate)) / 1000)
|
||
timeElement.element.textContent = `最后更新: ${lastUpdate} (${elapsed}秒前)`
|
||
}
|
||
}
|
||
}
|
||
|
||
// 更新UI
|
||
function updateUI() {
|
||
// 更新数据卡片
|
||
const container = game.getSceneElement('data-container')
|
||
if (container) {
|
||
// 清空现有内容
|
||
container.element.innerHTML = ''
|
||
|
||
// 添加新的数据卡片
|
||
dataItems.forEach(item => {
|
||
const card = document.createElement('div')
|
||
card.className = 'data-card'
|
||
card.innerHTML = `
|
||
<div class="card-title">${item.title}</div>
|
||
<div class="card-value">${item.value}</div>
|
||
`
|
||
container.element.appendChild(card)
|
||
})
|
||
}
|
||
}
|
||
|
||
// 刷新数据
|
||
function refreshData() {
|
||
loadData()
|
||
}
|
||
|
||
// 处理在线状态
|
||
function handleOnline() {
|
||
updateStatus('在线')
|
||
}
|
||
|
||
// 处理离线状态
|
||
function handleOffline() {
|
||
updateStatus('离线')
|
||
}
|
||
|
||
// 恢复动画
|
||
function resumeAnimations() {
|
||
console.log('恢复动画')
|
||
}
|
||
|
||
// 暂停动画
|
||
function pauseAnimations() {
|
||
console.log('暂停动画')
|
||
}
|
||
|
||
// 保存当前状态
|
||
function saveCurrentState() {
|
||
console.log('保存当前状态')
|
||
}
|
||
|
||
// 清理资源
|
||
function cleanup() {
|
||
// 停止所有定时器
|
||
stopAutoRefresh()
|
||
|
||
// 移除事件监听器
|
||
window.removeEventListener('online', handleOnline)
|
||
window.removeEventListener('offline', handleOffline)
|
||
|
||
// 清理数据
|
||
dataItems = []
|
||
status = ''
|
||
lastUpdate = ''
|
||
|
||
console.log('资源清理完成')
|
||
}
|
||
</script>
|
||
```
|
||
|
||
## 生命周期最佳实践
|
||
|
||
### 1. 合理分配操作到不同钩子
|
||
|
||
```javascript
|
||
// 正确的做法
|
||
onLoad(() => {
|
||
// 一次性初始化操作
|
||
initializeDatabase()
|
||
setupGlobalEventListeners()
|
||
})
|
||
|
||
onShow(() => {
|
||
// 每次显示时的操作
|
||
startDataPolling()
|
||
resumeAnimations()
|
||
})
|
||
|
||
onHide(() => {
|
||
// 隐藏时的操作
|
||
stopDataPolling()
|
||
pauseAnimations()
|
||
})
|
||
|
||
onDestory(() => {
|
||
// 销毁时的操作
|
||
cleanupResources()
|
||
removeEventListeners()
|
||
})
|
||
```
|
||
|
||
### 2. 及时清理资源
|
||
|
||
```javascript
|
||
onLoad(() => {
|
||
// 创建定时器
|
||
this.timer = setInterval(updateData, 5000)
|
||
|
||
// 添加事件监听器
|
||
document.addEventListener('keydown', handleKeyDown)
|
||
})
|
||
|
||
onDestory(() => {
|
||
// 清理定时器
|
||
if (this.timer) {
|
||
clearInterval(this.timer)
|
||
this.timer = null
|
||
}
|
||
|
||
// 移除事件监听器
|
||
document.removeEventListener('keydown', handleKeyDown)
|
||
})
|
||
```
|
||
|
||
### 3. 处理异步操作
|
||
|
||
```javascript
|
||
onLoad(async () => {
|
||
try {
|
||
// 异步加载数据
|
||
this.data = await loadDataFromServer()
|
||
updateUI()
|
||
} catch (error) {
|
||
console.error('加载数据失败:', error)
|
||
showErrorMessage()
|
||
}
|
||
})
|
||
|
||
onDestory(() => {
|
||
// 取消未完成的请求
|
||
if (this.currentRequest) {
|
||
this.currentRequest.cancel()
|
||
}
|
||
})
|
||
```
|
||
|
||
通过以上内容,你已经了解了PE引擎的生命周期机制。这些生命周期钩子为你提供了强大的控制能力,让你能够精确管理场景的创建、显示、隐藏和销毁过程。 |