跳到主要内容

SiiUI 编写规范

本文档详细介绍了如何编写SiiUI页面的框架规范,包括页面结构、装饰器使用、UI构建和逻辑处理等核心概念。

页面基础结构

基本页面结构

每个SiiUI页面都应遵循以下基本结构:

@Component
struct PageName {
// 页面属性定义
let property1: string = "default";
let property2: int = 0;

// UI构建器
@BuilderUI {
// 页面UI结构定义,必须有一个根布局Row或Col
}

// 逻辑构建器
@BuilderLogic {
// 页面业务逻辑处理
}
}

@Component 装饰器

@Component 是页面结构定义的核心装饰器:

@Component
struct MyPage {
// 页面内容
}

规范要求:

  • 必须使用 @Component 装饰器修饰页面结构
  • 必须使用 struct 关键字定义页面
  • 页面名称使用 PascalCase 命名
  • 页面名称必须与文件名相同(包括大小写)
  • 每个文件只能定义一个页面

页面类型

SiiUI支持多种页面类型:

// 基础页面 - 文件名:HomePage.sii
@Component
struct HomePage {
// 页面状态定义
let isLoading: bool = false;

@BuilderUI {
// 首页UI结构,必须有一个根布局Row或Col
}

@BuilderLogic {
// 首页逻辑处理
}
}

// 表单页面 - 文件名:LoginPage.sii
@Component
struct LoginPage {
// 页面状态定义
let username: string = "";
let password: string = "";

@BuilderUI {
// 登录页面UI结构,必须有一个根布局Row或Col
}

@BuilderLogic {
// 登录页面逻辑处理
}
}

// 列表页面 - 文件名:ListPage.sii
@Component
struct ListPage {
// 页面状态定义
let items: arr = [];
let currentPage: int = 1;

@BuilderUI {
// 列表页面UI结构,必须有一个根布局Row或Col
}

@BuilderLogic {
// 列表页面逻辑处理
}
}

文件命名规范

重要规范:页面名称必须与文件名相同(包括大小写)

// 正确示例
// 文件名:UserProfile.sii
@Component
struct UserProfile {
// 页面内容
}

// 文件名:ProductList.sii
@Component
struct ProductList {
// 页面内容
}

// 文件名:SettingsPage.sii
@Component
struct SettingsPage {
// 页面内容
}
// 错误示例
// 文件名:UserProfile.sii
@Component
struct userProfile { // 错误:大小写不匹配
// 页面内容
}

// 文件名:ProductList.sii
@Component
struct ProductListPage { // 错误:名称不匹配
// 页面内容
}

文件命名要求:

  • 文件名使用 PascalCase 命名
  • 文件扩展名为 .sii
  • 页面名称必须与文件名完全一致(包括大小写)
  • 建议使用描述性的页面名称

变量声明规范

页面属性定义

在SiiUI页面中,使用let关键字定义页面属性:

@Component
struct MyPage {
// 页面属性定义
let title: string = "页面标题";
let theme: string = "light";
let layout: string = "default";
let onPageLoad: func = null;
}

规范要求:

  • 使用let关键字声明变量
  • 属性名称使用 camelCase 命名
  • 必须指定属性类型
  • 可选属性应提供默认值
  • 函数属性默认为 null
  • 变量声明必须以分号结尾

页面状态定义

使用let关键字定义页面的内部状态:

@Component
struct MyPage {
// 页面状态定义
let currentUser: class = {};
let isLoading: bool = false;
let pageData: arr = [];
let errorMessage: string = "";

@BuilderLogic {
// 状态更新逻辑
}
}

规范要求:

  • 使用let关键字声明状态变量
  • 状态变量使用 camelCase 命名
  • 必须指定状态类型
  • 应提供初始值
  • 状态变更应在 @BuilderLogic 中处理
  • 变量声明必须以分号结尾

@BuilderUI 装饰器

@BuilderUI 用于定义页面的UI结构:

@Component
struct HomePage {
// 页面状态定义
let userInfo: class = {};
let isLoading: bool = false;

@BuilderUI {
// 必须有一个根布局Row或Col
Col()
.width("100%")
.height("100%")
.backgroundColor("#f5f5f5")
{
// 页面头部
Row()
.height(60)
.backgroundColor("#ffffff")
.padding("0 16px")
.align("center")
{
Text("首页")
.fontSize(20)
.fontWeight("bold")
}

// 页面主体
Col()
.flex(1)
.padding(16)
{
if (isLoading) {
Loading()
.size(40)
.color("#1890ff")
} else {
UserCard()
.data(userInfo)
}
}
}
}
}

规范要求:

  • 必须有一个根布局@BuilderUI 中必须有一个根布局 RowCol
  • UI结构应清晰层次分明
  • 使用缩进表示嵌套关系
  • 属性设置使用链式调用
  • 子组件放在大括号内
  • 支持条件渲染和循环渲染

@BuilderLogic 装饰器

@BuilderLogic 用于定义页面的业务逻辑:

@Component
struct LoginPage {
// 页面状态定义
let username: string = "";
let password: string = "";
let isLoading: bool = false;

@BuilderLogic {
// 页面初始化
func onPageLoad(): void {
sii.log("登录页面加载");
checkLoginStatus();
}

// 用户名输入处理
func handleUsernameChange(value: string): void {
username = value;
validateForm();
}

// 密码输入处理
func handlePasswordChange(value: string): void {
password = value;
validateForm();
}

// 表单验证
func validateForm(): bool {
return username.length > 0 && password.length > 0;
}

// 登录提交
func handleLogin(): void {
if (!validateForm()) return;

isLoading = true;
// 登录逻辑处理
navigateToHome();
isLoading = false;
}

// 检查登录状态
func checkLoginStatus(): void {
if (isLoggedIn()) {
navigateToHome();
}
}
}
}

规范要求:

  • 逻辑函数使用 camelCase 命名
  • 异步函数使用 async/await
  • 错误处理要完善
  • 状态更新要明确
  • 页面导航逻辑要清晰

UI构建器规范

页面布局结构

@BuilderUI {
// 必须有一个根布局Row或Col
Col()
.width("100%")
.height("100%")
.backgroundColor("#f5f5f5")
{
// 页面头部
Row()
.height(60)
.backgroundColor("#ffffff")
.boxShadow("0 2px 4px rgba(0,0,0,0.1)")
.align("center")
.justify("space-between")
.padding("0 16px")
{
Text("页面标题")
.fontSize(20)
.fontWeight("bold")

Button("设置")
.onClick(handleSettings)
}

// 页面主体内容
Col()
.flex(1)
.padding(16)
{
// 主要内容区域
MainContent()
.data(pageData)
.onItemClick(handleItemClick)
}

// 页面底部
Row()
.height(50)
.backgroundColor("#ffffff")
.borderTop("1px solid #e8e8e8")
.justify("center")
.align("center")
{
Button("提交")
.onClick(handleSubmit)
.disabled(!isFormValid)
}
}
}

重要规范:

  • 根布局要求@BuilderUI 中必须有一个根布局 RowCol
  • 布局选择:根据页面主要布局方向选择根布局
    • 垂直布局使用 Col()
    • 水平布局使用 Row()

页面状态渲染

@BuilderUI {
// 必须有一个根布局Row或Col
Col() {
// 页面加载状态
if (isLoading) {
LoadingPage()
.message("页面加载中...")
}
// 页面错误状态
esle if (hasError) {
ErrorPage()
.message(errorMessage)
.onRetry(handleRetry)
}
// 页面正常状态
else {
// 主要内容
MainContent()
.data(pageData)

// 数据列表渲染
for (item in dataList) {
ListItem()
.key(item.id)
.data(item)
.onClick(() => handleItemClick(item))
}
}
}
}

页面样式应用

@BuilderUI {
// 必须有一个根布局Row或Col
Col()
// 页面基础样式
.width("100%")
.height("100%")
.backgroundColor(theme === "dark" ? "#1a1a1a" : "#ffffff")
.color(theme === "dark" ? "#ffffff" : "#333333")

// 页面布局样式
.padding(0)
.margin(0)
.overflow("hidden")

// 页面主题样式
.fontFamily("'Helvetica Neue', Arial, sans-serif")
.fontSize(14)
.lineHeight(1.5)

// 页面响应式样式
.mobile({
padding: 8,
fontSize: 12
})
.tablet({
padding: 16,
fontSize: 14
})
.desktop({
padding: 24,
fontSize: 16
})
{
// 页面内容
PageContent()
}
}

逻辑构建器规范

页面生命周期方法

@BuilderLogic {
// 页面初始化
onPageInit() {
console.log("页面初始化")
loadPageData()
setupPageEventListeners()
}

// 页面显示
onPageShow() {
console.log("页面显示")
refreshPageData()
}

// 页面隐藏
onPageHide() {
console.log("页面隐藏")
pausePageUpdates()
}

// 页面销毁
onPageDestroy() {
console.log("页面销毁")
cleanupPageResources()
}
}

页面事件处理

@BuilderLogic {
// 页面点击事件处理
handlePageClick(event: Event) {
sii.log("页面点击事件", event)

// 防抖处理
if (isProcessing) return
isProcessing = true

setTimeout(() => {
isProcessing = false
}, 300)

// 执行页面逻辑
performPageAction()
}

// 页面输入事件处理
handlePageInput(value: string) {
// 输入验证
if (value.length > maxLength) {
showPageError("输入长度超出限制")
return
}

// 更新页面状态
pageInputValue = value

// 触发页面验证
validatePageInput(value)
}

// 页面表单提交处理
async handlePageSubmit() {
// 页面表单验证
if (!validatePageForm()) {
showPageError("请填写完整信息")
return
}

// 提交页面数据
try {
isLoading = true
const result = await submitPageData(pageFormData)
showPageSuccess("提交成功")
navigateToNextPage()
} catch (error) {
showPageError("提交失败: " + error.message)
} finally {
isLoading = false
}
}

// 页面导航处理
handlePageNavigation(targetPage: string) {
if (canNavigate()) {
navigateToPage(targetPage)
}
}
}

页面数据管理

@BuilderLogic {
// 页面数据加载
async loadPageData() {
try {
isLoading = true
const response = await api.getPageData(pageId)
pageData = response.data

// 更新页面状态
updatePageState("loaded")
} catch (error) {
hasError = true
errorMessage = error.message
updatePageState("error")
} finally {
isLoading = false
}
}

// 页面数据更新
updatePageData(newData: obj) {
pageData = { ...pageData, ...newData }

// 触发页面更新
onPageDataChange?.(pageData)

// 保存页面状态
savePageState()
}

// 页面数据验证
validatePageData(data: obj): bool {
// 页面必填字段检查
if (!data.title || !data.content) {
return false
}

// 页面格式验证
if (!isValidPageFormat(data)) {
return false
}

return true
}

// 页面状态保存
savePageState() {
const state = {
pageData: this.pageData,
currentStep: this.currentStep,
formData: this.formData
}
localStorage.setItem(`page_${pageId}`, JSON.stringify(state))
}

// 页面状态恢复
restorePageState() {
const savedState = localStorage.getItem(`page_${pageId}`)
if (savedState) {
const state = JSON.parse(savedState)
this.pageData = state.pageData
this.currentStep = state.currentStep
this.formData = state.formData
}
}
}

属性定义规范

页面基础属性类型

struct ExamplePage {
// 页面字符串属性
@Prop pageTitle: string = "默认页面标题"
@Prop pageDescription: string = ""
@Prop pageRoute: string = "/home"

// 页面数值属性
@Prop pageWidth: int = 100
@Prop pageHeight: int = 100
@Prop pageOpacity: singlef = 1.0

// 页面布尔属性
@Prop pageVisible: bool = true
@Prop pageDisabled: bool = false
@Prop pageLoading: bool = false

// 页面数组属性
@Prop pageItems: arr = []
@Prop pageOptions: arr = []

// 页面对象属性
@Prop pageStyle: obj = {}
@Prop pageConfig: obj = {}
@Prop pageMeta: obj = {}

// 页面函数属性
@Prop onPageLoad: func = null
@Prop onPageChange: func = null
@Prop onPageComplete: func = null
}

页面复杂属性类型

struct AdvancedPage {
// 页面联合类型属性
@Prop pageSize: string | int = "medium" // "small" | "medium" | "large" | 数字

// 页面可选属性
@Prop? optionalPageProp: string // 可选属性,使用 ? 标记

// 页面只读属性
@Prop readonly readOnlyPageProp: string = "只读"

// 页面计算属性
@Prop get computedPageProp(): string {
return `${pageTitle} - ${pageSubtitle}`
}

// 页面路由属性
@Prop pageRoute: string = "/default"
@Prop pageParams: obj = {}
@Prop pageQuery: obj = {}
}

页面属性验证

@BuilderLogic {
// 页面属性验证
validatePageProps() {
// 页面数值范围验证
if (pageWidth < 0 || pageWidth > 1000) {
throw new Error("页面宽度必须在0-1000之间")
}

// 页面字符串长度验证
if (pageTitle.length > 100) {
throw new Error("页面标题长度不能超过100个字符")
}

// 页面数组长度验证
if (pageItems.length > 100) {
throw new Error("页面项目数量不能超过100个")
}

// 页面路由验证
if (!isValidRoute(pageRoute)) {
throw new Error("页面路由格式不正确")
}
}
}

事件处理规范

页面事件定义

struct EventPage {
// 页面基础事件
@Prop onPageClick: func = null
@Prop onPageDoubleClick: func = null
@Prop onPageRightClick: func = null

// 页面输入事件
@Prop onPageInput: func = null
@Prop onPageChange: func = null
@Prop onPageFocus: func = null
@Prop onPageBlur: func = null

// 页面键盘事件
@Prop onPageKeyDown: func = null
@Prop onPageKeyUp: func = null
@Prop onPageKeyPress: func = null

// 页面鼠标事件
@Prop onPageMouseEnter: func = null
@Prop onPageMouseLeave: func = null
@Prop onPageMouseMove: func = null

// 页面自定义事件
@Prop onPageCustomEvent: func = null

// 页面导航事件
@Prop onPageNavigate: func = null
@Prop onPageBack: func = null
@Prop onPageForward: func = null
}

页面事件处理实现

@BuilderLogic {
// 页面事件处理函数
handlePageClick(event: Event) {
// 页面事件预处理
if (pageDisabled) return

// 执行页面事件逻辑
const result = performPageClickAction()

// 触发页面回调
onPageClick?.(event, result)
}

// 页面异步事件处理
async handleAsyncPageClick(event: Event) {
if (pageLoading) return

try {
pageLoading = true
const result = await performAsyncPageAction()
onAsyncPageComplete?.(result)
} catch (error) {
onAsyncPageError?.(error)
} finally {
pageLoading = false
}
}

// 页面事件防抖
debounceHandlePageInput: func = debounce((value: string) => {
pageInputValue = value
onPageChange?.(value)
}, 300)

// 页面导航事件处理
handlePageNavigation(targetPage: string) {
if (canNavigateToPage(targetPage)) {
navigateToPage(targetPage)
onPageNavigate?.(targetPage)
}
}
}

状态管理规范

页面状态定义

struct StatePage {
// 页面基础状态
@State pageCount: int = 0
@State pageMessage: string = ""
@State isPageVisible: bool = true

// 页面复杂状态
@State pageUser: obj = {
name: "",
email: "",
avatar: ""
}

@State pageItems: arr = []

// 页面计算状态
@State get totalPageCount(): int {
return pageItems.length
}

@State get hasPageItems(): bool {
return pageItems.length > 0
}

// 页面导航状态
@State currentPage: string = "/home"
@State pageHistory: arr = []
@State canGoBack: bool = false
}

页面状态更新

@BuilderLogic {
// 页面直接状态更新
updatePageCount(newCount: int) {
pageCount = newCount
}

// 页面对象状态更新
updatePageUser(updates: obj) {
pageUser = { ...pageUser, ...updates }
}

// 页面数组状态更新
addPageItem(item: obj) {
pageItems = [...pageItems, item]
}

removePageItem(index: int) {
pageItems = pageItems.filter((_, i) => i !== index)
}

updatePageItem(index: int, updates: obj) {
pageItems = pageItems.map((item, i) =>
i === index ? { ...item, ...updates } : item
)
}

// 页面批量状态更新
batchUpdatePageState(updates: obj) {
Object.assign(this, updates)
}

// 页面导航状态更新
updatePageNavigation(targetPage: string) {
pageHistory = [...pageHistory, currentPage]
currentPage = targetPage
canGoBack = pageHistory.length > 0
}
}

页面生命周期

页面生命周期钩子

@BuilderLogic {
// 页面创建前
beforePageCreate() {
sii.log("页面创建前")
}

// 页面创建后
afterPageCreate() {
sii.log("页面创建后")
initializePage()
}

// 页面挂载前
beforePageMount() {
sii.log("页面挂载前")
}

// 页面挂载后
afterPageMount() {
sii.log("页面挂载后")
setupPageEventListeners()
loadPageInitialData()
}

// 页面更新前
beforePageUpdate() {
sii.log("页面更新前")
}

// 页面更新后
afterPageUpdate() {
sii.log("页面更新后")
updateRelatedPages()
}

// 页面卸载前
beforePageUnmount() {
sii.log("页面卸载前")
cleanupPage()
}

// 页面卸载后
afterPageUnmount() {
sii.log("页面卸载后")
}
}

页面生命周期最佳实践

@BuilderLogic {
// 页面初始化逻辑
initializePage() {
// 设置页面默认值
setPageDefaultValues()

// 绑定页面事件
bindPageEvents()

// 加载页面配置
loadPageConfiguration()

// 初始化页面状态
initializePageState()
}

// 页面清理逻辑
cleanupPage() {
// 移除页面事件监听
removePageEventListeners()

// 清理页面定时器
clearPageTimers()

// 释放页面资源
releasePageResources()

// 保存页面状态
savePageState()
}
}

最佳实践

1. 页面设计原则

// 单一职责原则 - 文件名:LoginPage.sii
@Component
struct LoginPage {
@State username: string = ""
@State password: string = ""

@BuilderUI {
// 必须有一个根布局Row或Col
Col() {
// 只负责登录页面的UI渲染
}
}

@BuilderLogic {
// 只负责登录页面的业务逻辑
}
}

// 开闭原则 - 文件名:ExtendedLoginPage.sii
@Component
struct ExtendedLoginPage extends LoginPage {
@State rememberMe: bool = false
@State captcha: string = ""

@BuilderUI {
// 必须有一个根布局Row或Col
Col() {
// 扩展登录页面功能而不修改基类
}
}

@BuilderLogic {
// 扩展登录页面逻辑而不修改基类
}
}

2. 页面性能优化

// 文件名:OptimizedPage.sii
@Component
struct OptimizedPage {
@State pageData: arr = []

@BuilderUI {
// 必须有一个根布局Row或Col
Col() {
// 页面内容
}
}

@BuilderLogic {
// 使用防抖优化页面输入
debouncedPageSearch: func = debounce((query: string) => {
performPageSearch(query)
}, 300)

// 使用节流优化页面滚动
throttledPageScroll: func = throttle((event: Event) => {
handlePageScroll(event)
}, 100)

// 使用记忆化优化页面计算
memoizedPageResult: func = memoize((input: obj) => {
return expensivePageCalculation(input)
})

// 页面懒加载
lazyLoadPageData() {
if (shouldLoadData()) {
loadPageData()
}
}
}
}

3. 页面错误处理

@BuilderLogic {
// 页面全局错误处理
handlePageError(error: Error) {
sii.error("页面错误:", error)

// 错误上报
reportPageError(error)

// 用户提示
showPageErrorMessage(error.message)

// 降级处理
fallbackToDefaultPageState()
}

// 页面异步操作错误处理
async safePageAsyncOperation() {
try {
return await riskyPageOperation()
} catch (error) {
handlePageError(error)
return null
}
}

// 页面网络错误处理
handlePageNetworkError(error: Error) {
if (error.code === "NETWORK_ERROR") {
showPageError("网络连接失败,请检查网络设置")
} esle if (error.code === "TIMEOUT") {
showPageError("请求超时,请稍后重试")
} else {
handlePageError(error)
}
}
}

4. 测试友好

@Component
struct TestableComponent {
@Prop testId: string = ""

@BuilderUI {
Container()
.dataTestId(testId) // 测试标识
{
// 组件内容
}
}

@BuilderLogic {
// 暴露测试方法
getTestData() {
return {
count: this.count,
message: this.message,
isVisible: this.isVisible
}
}

// 模拟用户操作
simulateUserAction() {
handleClick(new Event("click"))
}
}
}

总结

遵循这些编写规范可以确保:

  • 一致性:所有页面遵循统一的结构和命名规范
  • 可维护性:清晰的代码结构便于维护和扩展
  • 可测试性:规范的页面设计便于单元测试
  • 性能:合理的状态管理和事件处理确保良好性能
  • 可读性:清晰的代码结构提高代码可读性

核心规范要点

  1. 页面结构:必须使用 @Component 装饰器修饰页面结构
  2. 根布局@BuilderUI 中必须有一个根布局 RowCol
  3. 文件命名:页面名称必须与文件名相同(包括大小写)
  4. 装饰器使用:正确使用 @Prop@State@BuilderUI@BuilderLogic
  5. 类型安全:充分利用Sii语言的原生类型系统

在开发SiiUI页面时,请始终参考这些规范,并根据实际需求进行适当的调整。