You've already forked Pandona-Engine
377 lines
7.0 KiB
Markdown
377 lines
7.0 KiB
Markdown
# 场景系统
|
||
|
||
PE引擎的场景系统是其核心特性之一,它提供了一种结构化的方式来组织和管理应用的不同视图和状态。每个场景都是一个独立的单元,包含模板、样式和逻辑代码。
|
||
|
||
## 场景的基本结构
|
||
|
||
PE场景由三个主要部分组成:
|
||
|
||
1. **模板(Template)** - 定义场景的结构和元素
|
||
2. **样式(Style)** - 定义场景的外观和样式
|
||
3. **脚本(Script)** - 定义场景的逻辑和行为
|
||
|
||
### 场景文件结构
|
||
|
||
一个典型的PE场景目录结构如下:
|
||
|
||
```
|
||
scenes/
|
||
├── home/
|
||
│ ├── index.pe # 场景模板文件
|
||
│ └── index.less # 场景样式文件
|
||
└── about/
|
||
├── index.pe
|
||
└── index.less
|
||
```
|
||
|
||
## 场景模板文件(.pe)
|
||
|
||
场景模板文件使用类似HTML的语法,包含`sence`标签和`script`标签:
|
||
|
||
```html
|
||
<sence>
|
||
<!-- 场景元素定义 -->
|
||
<sprite class="logo"></sprite>
|
||
<box class="welcome-box">欢迎来到PE引擎!</box>
|
||
<text class="description">这是一个简单的场景示例</text>
|
||
|
||
<!-- 循环渲染元素 -->
|
||
<box for="{item} in menuItems"
|
||
class="menu-item"
|
||
@click="handleMenuClick(item.id)">
|
||
{{ item.label }}
|
||
</box>
|
||
</sence>
|
||
|
||
<script>
|
||
// 场景数据和逻辑
|
||
const menuItems = [
|
||
{ id: 'home', label: '首页' },
|
||
{ id: 'about', label: '关于' },
|
||
{ id: 'contact', label: '联系' }
|
||
]
|
||
|
||
// 生命周期钩子
|
||
onLoad(() => {
|
||
console.log('场景加载完成')
|
||
})
|
||
|
||
onShow(() => {
|
||
console.log('场景显示')
|
||
})
|
||
|
||
// 事件处理函数
|
||
function handleMenuClick(id) {
|
||
console.log('点击了菜单项:', id)
|
||
PE.navigateTo(`/${id}`)
|
||
}
|
||
</script>
|
||
```
|
||
|
||
### 模板语法
|
||
|
||
PE场景模板支持以下语法特性:
|
||
|
||
#### 元素定义
|
||
|
||
```html
|
||
<!-- 基本元素 -->
|
||
<sprite class="my-sprite" x="100" y="100" width="50" height="50"></sprite>
|
||
<box class="my-box">盒子内容</box>
|
||
<text class="my-text">文本内容</text>
|
||
```
|
||
|
||
#### 事件绑定
|
||
|
||
使用`@`前缀绑定事件处理器:
|
||
|
||
```html
|
||
<box @click="handleClick" @mouseenter="handleMouseEnter">点击我</box>
|
||
```
|
||
|
||
#### 循环渲染
|
||
|
||
使用`for`指令循环渲染元素:
|
||
|
||
```html
|
||
<box for="{item} in items" class="item">{{ item.name }}</box>
|
||
```
|
||
|
||
#### 插值表达式
|
||
|
||
使用双大括号语法插入数据:
|
||
|
||
```html
|
||
<text>当前计数: {{ count }}</text>
|
||
```
|
||
|
||
## 场景样式文件(.less)
|
||
|
||
每个场景可以有对应的Less样式文件,样式会自动作用于该场景内的元素:
|
||
|
||
```less
|
||
// home/index.less
|
||
.logo {
|
||
width: 100px;
|
||
height: 100px;
|
||
background-color: #3498db;
|
||
border-radius: 50%;
|
||
position: absolute;
|
||
top: 50px;
|
||
left: 50px;
|
||
}
|
||
|
||
.welcome-box {
|
||
width: 300px;
|
||
height: 100px;
|
||
background-color: #2c3e50;
|
||
color: white;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: absolute;
|
||
top: 200px;
|
||
left: 50px;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.description {
|
||
color: #7f8c8d;
|
||
font-size: 16px;
|
||
position: absolute;
|
||
top: 320px;
|
||
left: 50px;
|
||
}
|
||
|
||
.menu-item {
|
||
width: 150px;
|
||
height: 40px;
|
||
background-color: #e74c3c;
|
||
color: white;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: absolute;
|
||
left: 50px;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
|
||
// 使用Less变量和嵌套
|
||
&:hover {
|
||
background-color: darken(#e74c3c, 10%);
|
||
}
|
||
|
||
&:nth-child(1) { top: 380px; }
|
||
&:nth-child(2) { top: 430px; }
|
||
&:nth-child(3) { top: 480px; }
|
||
}
|
||
```
|
||
|
||
## 场景路由配置
|
||
|
||
场景通过`sences.json`文件进行路由配置:
|
||
|
||
```json
|
||
{
|
||
"sence": [
|
||
{
|
||
"path": "/",
|
||
"title": "首页"
|
||
},
|
||
{
|
||
"path": "/about",
|
||
"title": "关于我们"
|
||
},
|
||
{
|
||
"path": "/products",
|
||
"title": "产品"
|
||
}
|
||
],
|
||
"platform": "PC"
|
||
}
|
||
```
|
||
|
||
## 场景生命周期
|
||
|
||
每个场景都有完整的生命周期钩子,让你能够在适当的时机执行操作:
|
||
|
||
### onLoad
|
||
|
||
场景加载时调用,只在场景首次加载时执行一次:
|
||
|
||
```javascript
|
||
onLoad(() => {
|
||
console.log('场景加载完成')
|
||
// 初始化操作
|
||
initializeData()
|
||
})
|
||
```
|
||
|
||
### onShow
|
||
|
||
场景显示时调用,每次场景被显示时都会执行:
|
||
|
||
```javascript
|
||
onShow(() => {
|
||
console.log('场景显示')
|
||
// 每次显示时的操作
|
||
refreshData()
|
||
})
|
||
```
|
||
|
||
### onHide
|
||
|
||
场景隐藏时调用:
|
||
|
||
```javascript
|
||
onHide(() => {
|
||
console.log('场景隐藏')
|
||
// 清理操作
|
||
pauseAnimations()
|
||
})
|
||
```
|
||
|
||
### onDestory
|
||
|
||
场景销毁时调用:
|
||
|
||
```javascript
|
||
onDestory(() => {
|
||
console.log('场景销毁')
|
||
// 最终清理操作
|
||
clearInterval(timer)
|
||
})
|
||
```
|
||
|
||
## 场景间导航
|
||
|
||
PE提供了简单的API来在场景间进行导航:
|
||
|
||
```javascript
|
||
// 导航到指定路径的场景
|
||
PE.navigateTo('/about')
|
||
|
||
// 在模板中使用
|
||
<box @click="PE.navigateTo('/products')">查看产品</box>
|
||
```
|
||
|
||
## 完整示例
|
||
|
||
以下是一个完整的场景示例:
|
||
|
||
### scenes/product/index.pe
|
||
|
||
```html
|
||
<sence>
|
||
<box class="header">产品列表</box>
|
||
|
||
<box for="{product} in products"
|
||
class="product-card"
|
||
@click="viewProduct(product.id)">
|
||
<text class="product-name">{{ product.name }}</text>
|
||
<text class="product-price">¥{{ product.price }}</text>
|
||
</box>
|
||
|
||
<box class="back-button" @click="PE.navigateTo('/')">返回首页</box>
|
||
</sence>
|
||
|
||
<script>
|
||
// 产品数据
|
||
const products = [
|
||
{ id: 1, name: '产品A', price: 99.99 },
|
||
{ id: 2, name: '产品B', price: 149.99 },
|
||
{ id: 3, name: '产品C', price: 199.99 }
|
||
]
|
||
|
||
// 生命周期钩子
|
||
onLoad(() => {
|
||
console.log('产品页面加载')
|
||
})
|
||
|
||
onShow(() => {
|
||
console.log('产品页面显示')
|
||
})
|
||
|
||
// 事件处理函数
|
||
function viewProduct(id) {
|
||
console.log('查看产品:', id)
|
||
// 可以通过全局变量或事件传递数据
|
||
window.currentProductId = id
|
||
PE.navigateTo('/product-detail')
|
||
}
|
||
</script>
|
||
```
|
||
|
||
### scenes/product/index.less
|
||
|
||
```less
|
||
.header {
|
||
width: 100%;
|
||
height: 60px;
|
||
background-color: #34495e;
|
||
color: white;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.product-card {
|
||
width: 300px;
|
||
height: 100px;
|
||
background-color: #ecf0f1;
|
||
border: 1px solid #bdc3c7;
|
||
border-radius: 8px;
|
||
position: absolute;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
padding: 0 20px;
|
||
cursor: pointer;
|
||
|
||
&:hover {
|
||
background-color: #d5dbdb;
|
||
}
|
||
|
||
&:nth-child(2) { top: 100px; } // 第一个产品卡
|
||
&:nth-child(3) { top: 220px; } // 第二个产品卡
|
||
&:nth-child(4) { top: 340px; } // 第三个产品卡
|
||
}
|
||
|
||
.product-name {
|
||
color: #2c3e50;
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.product-price {
|
||
color: #e74c3c;
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.back-button {
|
||
width: 100px;
|
||
height: 40px;
|
||
background-color: #95a5a6;
|
||
color: white;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: absolute;
|
||
bottom: 20px;
|
||
left: 20px;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
|
||
&:hover {
|
||
background-color: #7f8c8d;
|
||
}
|
||
}
|
||
```
|
||
|
||
通过以上内容,你已经了解了PE引擎的场景系统。在下一章节中,我们将探讨样式处理的相关内容。 |