# 生命周期

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引擎的生命周期机制。这些生命周期钩子为你提供了强大的控制能力，让你能够精确管理场景的创建、显示、隐藏和销毁过程。