Files
Pandona-Engine/guide/essentials/lifecycle.md
2025-10-03 16:49:53 +08:00

11 KiB
Raw Blame History

生命周期

PE引擎为场景提供了完整的生命周期钩子让你能够在适当的时机执行初始化、清理和其他操作。理解生命周期对于开发高效、稳定的PE应用至关重要。

生命周期钩子概览

每个PE场景都有四个主要的生命周期钩子

  1. onLoad - 场景加载时调用(只执行一次)
  2. onShow - 场景显示时调用(每次显示都会执行)
  3. onHide - 场景隐藏时调用
  4. onDestory - 场景销毁时调用(只执行一次)

onLoad

onLoad钩子在场景首次加载时调用,只执行一次。这是进行一次性初始化操作的最佳时机。

<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钩子在场景每次显示时调用。无论是首次显示还是从其他场景切换回来,都会执行此钩子。

<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钩子在场景隐藏时调用,比如切换到其他场景时。

<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钩子在场景销毁时调用,通常发生在应用关闭或场景被永久移除时。

<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

<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. 合理分配操作到不同钩子

// 正确的做法
onLoad(() => {
  // 一次性初始化操作
  initializeDatabase()
  setupGlobalEventListeners()
})

onShow(() => {
  // 每次显示时的操作
  startDataPolling()
  resumeAnimations()
})

onHide(() => {
  // 隐藏时的操作
  stopDataPolling()
  pauseAnimations()
})

onDestory(() => {
  // 销毁时的操作
  cleanupResources()
  removeEventListeners()
})

2. 及时清理资源

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. 处理异步操作

onLoad(async () => {
  try {
    // 异步加载数据
    this.data = await loadDataFromServer()
    updateUI()
  } catch (error) {
    console.error('加载数据失败:', error)
    showErrorMessage()
  }
})

onDestory(() => {
  // 取消未完成的请求
  if (this.currentRequest) {
    this.currentRequest.cancel()
  }
})

通过以上内容你已经了解了PE引擎的生命周期机制。这些生命周期钩子为你提供了强大的控制能力让你能够精确管理场景的创建、显示、隐藏和销毁过程。