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中必须有一个根布局Row或Col - 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中必须有一个根布局Row或Col - 布局选择:根据页面主要布局方向选择根布局
- 垂直布局使用
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"))
}
}
}
总结
遵循这些编写规范可以确保:
- 一致性:所有页面遵循统一的结构和命名规范
- 可维护性:清晰的代码结构便于维护和扩展
- 可测试性:规范的页面设计便于单元测试
- 性能:合理的状态管理和事件处理确保良好性能
- 可读性:清晰的代码结构提高代码可读性
核心规范要点
- 页面结构:必须使用
@Component装饰器修饰页面结构 - 根布局:
@BuilderUI中必须有一个根布局Row或Col - 文件命名:页面名称必须与文件名相同(包括大小写)
- 装饰器使用:正确使用
@Prop、@State、@BuilderUI、@BuilderLogic - 类型安全:充分利用Sii语言的原生类型系统
在开发SiiUI页面时,请始终参考这些规范,并根据实际需求进行适当的调整。