概述HarmonyOS NEXT鸿蒙星河版作为华为打造的纯血鸿蒙系统其应用开发体系基于ArkTS语言和ArkUI框架。ArkTS在TypeScript基础上扩展了声明式UI、状态管理等特性而组件化开发则是构建复杂应用的核心思想。本文将从面向对象基础到组件化UI实践通过完整实例详解鸿蒙NEXT应用开发全流程。一、ArkTS面向对象基础1.1 类与对象ArkTS作为鸿蒙生态的主力开发语言在TypeScript基础上扩展了声明式UI能力同时完整支持面向对象编程范式。类的定义类是用于创建对象的模板同时类声明也会引入一个新类型可定义其实例属性、方法和构造函数。typescript// 定义一个Person类 class Person { // 属性声明 name: string; age: number; // 构造函数 constructor(name: string, age: number) { this.name name; this.age age; } // 方法定义 introduce(): string { return 我叫${this.name}今年${this.age}岁; } } // 创建对象实例 let person new Person(张三, 25); console.log(person.introduce());1.2 访问修饰符与继承ArkTS支持public、private、protected等访问修饰符以及类的继承机制。typescript// 基类 class Animal { protected name: string; constructor(name: string) { this.name name; } makeSound(): void { console.log(${this.name}发出声音); } } // 派生类 class Dog extends Animal { private breed: string; // 品种私有属性 constructor(name: string, breed: string) { super(name); // 调用父类构造函数 this.breed breed; } // 方法重写 makeSound(): void { console.log(${this.name}${this.breed}汪汪叫); } // 特有方法 fetch(): void { console.log(${this.name}在接飞盘); } } let dog new Dog(旺财, 金毛); dog.makeSound(); // 输出旺财金毛汪汪叫 dog.fetch(); // 输出旺财在接飞盘1.3 接口与类型别名接口用于定义对象的结构和契约是实现组件间解耦的重要工具。typescript// 定义用户接口 interface User { id: number; name: string; email?: string; // 可选属性 readonly createdAt: Date; // 只读属性 } // 实现接口 class Member implements User { id: number; name: string; email?: string; readonly createdAt: Date; constructor(id: number, name: string, email?: string) { this.id id; this.name name; this.email email; this.createdAt new Date(); } } // 函数接口 interface SearchFunc { (source: string, subString: string): boolean; } let mySearch: SearchFunc function(src: string, sub: string): boolean { return src.includes(sub); };1.4 装饰器ArkTS大量使用装饰器来实现声明式UI和状态管理这是其核心特性之一。typescript// 类装饰器 function sealed(constructor: Function) { Object.seal(constructor); Object.seal(constructor.prototype); } sealed class Greeter { greeting: string; constructor(message: string) { this.greeting message; } greet() { return Hello, ${this.greeting}; } }二、ArkTS组件化UI开发2.1 声明式UI基础ArkUI方舟开发框架提供基于ArkTS的声明式开发范式通过简洁的语法描述UI状态和结构。核心概念Component装饰struct使其具有组件化能力Entry标记页面入口组件build函数定义组件的UI描述typescriptEntry Component struct HelloComponent { State message: string Hello, HarmonyOS NEXT!; build() { Row() { Column() { Text(this.message) .fontSize(50) .fontWeight(FontWeight.Bold) .fontColor(Color.Blue) } .width(100%) } .height(100%) } }2.2 自定义组件创建自定义组件是UI复用的基本单位通过Component装饰器定义。typescript// 定义可复用的卡片组件 Component struct InfoCard { // 组件属性 private title: string ; private content: string ; private cardWidth: Length 300; build() { Column() { Text(this.title) .fontSize(20) .fontWeight(FontWeight.Bold) .width(100%) .textAlign(TextAlign.Center) .padding(10) .backgroundColor(#f0f0f0) Text(this.content) .fontSize(16) .padding(15) .width(100%) } .width(this.cardWidth) .borderRadius(10) .backgroundColor(Color.White) .shadow({ radius: 10, color: #888888 }) } } // 使用自定义组件 Entry Component struct CardDemo { build() { Column({ space: 20 }) { InfoCard({ title: 鸿蒙特性, content: 一次开发多端部署可分可合自由流转 }) InfoCard({ title: ArkTS优势, content: 声明式UI、状态管理、跨端能力, cardWidth: 350 }) } .width(100%) .padding(20) } }2.3 布局与容器组件ArkUI提供多种布局容器实现灵活的界面排列。typescriptEntry Component struct LayoutDemo { build() { // 线性布局 Column({ space: 15 }) { Text(线性布局示例).fontSize(24).fontWeight(FontWeight.Bold) // Row水平布局 Row({ space: 10 }) { Text(左).backgroundColor(#ff6b6b).padding(15) Text(中).backgroundColor(#4ecdc4).padding(15) Text(右).backgroundColor(#ffe66d).padding(15) } .width(100%) .justifyContent(FlexAlign.SpaceAround) Divider() // 层叠布局 Stack({ alignContent: Alignment.BottomEnd }) { Image($r(app.media.background)) .width(300) .height(200) .objectFit(ImageFit.Cover) Text(底部文字) .backgroundColor(rgba(0,0,0,0.5)) .fontColor(Color.White) .padding(8) } .borderRadius(10) .margin({ top: 20 }) // 弹性布局 Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap, justifyContent: FlexAlign.SpaceBetween }) { ForEach(1 to 6, (item: number) { Text(项目${item}) .width(80) .height(80) .backgroundColor(#3498db) .fontColor(Color.White) .textAlign(TextAlign.Center) .borderRadius(8) .margin(5) }) } } .padding(20) .width(100%) } }三、状态管理深入3.1 组件内状态StateState装饰的变量是组件内部状态数据修改时会触发UI重新渲染。typescriptEntry Component struct CounterDemo { State count: number 0; State isActive: boolean false; build() { Column({ space: 20 }) { Text(当前计数: ${this.count}) .fontSize(30) .fontColor(this.isActive ? Color.Green : Color.Red) Row({ space: 15 }) { Button(增加) .onClick(() { this.count; if (this.count 10) this.isActive true; }) Button(减少) .onClick(() { this.count--; if (this.count 0) this.isActive false; }) Button(重置) .onClick(() { this.count 0; this.isActive false; }) } Text(this.isActive ? 活跃状态 : 非活跃状态) .fontSize(16) .fontColor(this.isActive ? Color.Green : Color.Gray) } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }3.2 父子组件通信Prop与LinkProp单向数据同步子组件接收父组件数据但不能修改。Link双向数据同步父子组件数据变更互相影响。typescript// 子组件 - 使用Prop单向接收 Component struct PropChild { Prop count: number; Prop title: string; build() { Column() { Text(this.title).fontSize(18).fontWeight(FontWeight.Bold) Text(Prop接收值: ${this.count}).fontSize(20).fontColor(Color.Blue) Button(尝试修改(无效)) .onClick(() { // this.count; // 错误Prop不允许修改 console.log(Prop不能直接修改); }) } .padding(15) .backgroundColor(#f8f9fa) .borderRadius(8) } } // 子组件 - 使用Link双向绑定 Component struct LinkChild { Link count: number; build() { Row({ space: 10 }) { Text(Link值: ${this.count}).fontSize(20) Button() .onClick(() this.count) Button(-) .onClick(() this.count--) } .padding(15) .backgroundColor(#e9ecef) .borderRadius(8) } } // 父组件 Entry Component struct ParentComponent { State parentCount: number 10; build() { Column({ space: 20 }) { Text(父组件状态: ${this.parentCount}) .fontSize(24) .fontWeight(FontWeight.Bold) PropChild({ count: this.parentCount, title: Prop示例 }) // 使用$符号创建Link双向绑定 LinkChild({ count: $parentCount }) Button(父组件增加) .onClick(() this.parentCount) } .padding(20) .width(100%) } }3.3 跨级组件通信Provide与ConsumeProvide和Consume实现祖先组件与后代组件之间的数据传递避免逐层传递。typescript// 祖先组件 Component struct GrandParent { Provide userInfo: string 初始用户; Provide theme: string light; build() { Column({ space: 20 }) { Text(祖父组件).fontSize(24) Text(当前用户: ${this.userInfo}) Button(切换主题) .onClick(() { this.theme this.theme light ? dark : light; }) Parent() } .padding(20) .width(100%) } } // 中间组件无需关心数据 Component struct Parent { build() { Column() { Text(父组件(中间层)) .fontSize(18) .fontColor(Color.Gray) Child() } .padding(10) } } // 后代组件 Component struct Child { Consume userInfo: string; Consume theme: string; build() { Column({ space: 15 }) { Text(孙组件).fontSize(20).fontWeight(FontWeight.Bold) Row() { Text(接收用户: ${this.userInfo}) Button(修改用户) .onClick(() { this.userInfo 新用户_ Math.floor(Math.random() * 100); }) } Text(当前主题: ${this.theme}) .fontColor(this.theme dark ? Color.Black : Color.Blue) } .padding(15) .backgroundColor(this.theme dark ? #333 : #f0f0f0) .borderRadius(8) } } Entry Component struct ProvideConsumeDemo { build() { GrandParent() } }3.4 对象状态管理Observed与ObjectLink对于嵌套对象需要使用Observed装饰类ObjectLink装饰对象属性。typescript// 被观察的类 Observed class Task { name: string; completed: boolean; subtasks: SubTask[]; constructor(name: string) { this.name name; this.completed false; this.subtasks []; } } Observed class SubTask { title: string; done: boolean; constructor(title: string) { this.title title; this.done false; } } Component struct SubTaskItem { ObjectLink subTask: SubTask; build() { Row({ space: 10 }) { Checkbox() .select(this.subTask.done) .onChange((value: boolean) { this.subTask.done value; }) Text(this.subTask.title) .decoration({ type: this.subTask.done ? TextDecorationType.LineThrough : TextDecorationType.None }) } .padding(5) } } Component struct TaskItem { ObjectLink task: Task; build() { Column() { Row({ space: 10 }) { Checkbox() .select(this.task.completed) .onChange((value: boolean) { this.task.completed value; }) Text(this.task.name) .fontSize(18) .fontWeight(FontWeight.Bold) } Column() { ForEach(this.task.subtasks, (sub: SubTask) { SubTaskItem({ subTask: sub }) }) } .padding({ left: 30 }) } .padding(10) .backgroundColor(#fafafa) .borderRadius(8) } } Entry Component struct TaskManager { State tasks: Task[] []; aboutToAppear() { let task1 new Task(学习鸿蒙); task1.subtasks.push(new SubTask(看文档)); task1.subtasks.push(new SubTask(写代码)); task1.subtasks.push(new SubTask(做测试)); let task2 new Task(项目开发); task2.subtasks.push(new SubTask(需求分析)); task2.subtasks.push(new SubTask(设计)); this.tasks [task1, task2]; } build() { Column({ space: 15 }) { Text(任务列表).fontSize(24).fontWeight(FontWeight.Bold) ForEach(this.tasks, (task: Task) { TaskItem({ task: task }) }) Button(添加子任务) .onClick(() { if (this.tasks.length 0) { this.tasks[0].subtasks.push(new SubTask(新子任务)); } }) } .padding(20) .width(100%) } }四、综合应用实例智能笔记应用通过一个完整的智能笔记应用综合运用ArkTS面向对象特性和组件化UI开发能力。4.1 项目结构设计text├── entry │ ├── src/main/ets │ │ ├── entryability │ │ │ └── EntryAbility.ets │ │ ├── pages │ │ │ ├── Index.ets │ │ │ ├── NoteDetail.ets │ │ │ └── NoteEdit.ets │ │ ├── components │ │ │ ├── NoteCard.ets │ │ │ ├── SearchBar.ets │ │ │ └── CategoryTag.ets │ │ ├── models │ │ │ └── NoteModel.ets │ │ └── utils │ │ └── StorageUtil.ets │ └── module.json54.2 数据模型定义typescript// models/NoteModel.ets Observed export class Note { id: string; title: string; content: string; category: string; tags: string[]; createTime: number; updateTime: number; isFavorite: boolean; color: string; constructor(title: string, content: string, category: string 默认) { this.id Date.now().toString() Math.random().toString(36).substr(2, 9); this.title title; this.content content; this.category category; this.tags []; this.createTime Date.now(); this.updateTime Date.now(); this.isFavorite false; this.color this.getRandomColor(); } private getRandomColor(): string { const colors [#FFCDD2, #F8BBD9, #E1BEE7, #D1C4E9, #C5CAE9, #BBDEFB, #B3E5FC, #B2EBF2, #B2DFDB, #C8E6C9]; return colors[Math.floor(Math.random() * colors.length)]; } updateContent(content: string) { this.content content; this.updateTime Date.now(); } toggleFavorite() { this.isFavorite !this.isFavorite; } } // 笔记分类 export class Category { name: string; count: number; icon: Resource; constructor(name: string, icon: Resource) { this.name name; this.count 0; this.icon icon; } }4.3 可复用组件开发typescript// components/SearchBar.ets Component export struct SearchBar { Link searchText: string; State isFocused: boolean false; private onSearch?: (value: string) void; build() { Row() { Image($r(app.media.search)) .width(20) .height(20) .margin({ left: 12, right: 8 }) TextInput({ placeholder: 搜索笔记..., text: this.searchText }) .height(40) .backgroundColor(Color.Transparent) .onChange((value: string) { this.searchText value; this.onSearch?.(value); }) .onFocus(() { this.isFocused true; }) .onBlur(() { this.isFocused false; }) if (this.searchText.length 0) { Button({ type: ButtonType.Circle }) { Image($r(app.media.close)) .width(16) .height(16) } .width(30) .height(30) .backgroundColor(#cccccc) .onClick(() { this.searchText ; this.onSearch?.(); }) .margin({ right: 8 }) } } .width(100%) .height(50) .backgroundColor(this.isFocused ? #f0f0f0 : #f5f5f5) .borderRadius(25) .padding({ right: 8 }) } } // components/NoteCard.ets Component export struct NoteCard { ObjectLink note: Note; private onCardClick?: () void; private onFavoriteClick?: () void; build() { Column() { Row() { // 分类标签 Text(this.note.category) .fontSize(12) .fontColor(#666666) .backgroundColor(#e0e0e0) .padding({ left: 8, right: 8, top: 2, bottom: 2 }) .borderRadius(10) Blank() // 收藏按钮 Image(this.note.isFavorite ? $r(app.media.favorite_filled) : $r(app.media.favorite)) .width(20) .height(20) .onClick((event) { event.stopPropagation(); this.onFavoriteClick?.(); }) } .width(100%) Text(this.note.title) .fontSize(18) .fontWeight(FontWeight.Bold) .width(100%) .maxLines(1) .textOverflow({ overflow: TextOverflow.Ellipsis }) .margin({ top: 8, bottom: 4 }) Text(this.note.content) .fontSize(14) .fontColor(#666666) .width(100%) .maxLines(2) .textOverflow({ overflow: TextOverflow.Ellipsis }) .margin({ bottom: 8 }) Row() { // 标签列表 Flex({ wrap: FlexWrap.Wrap, space: { left: 4, right: 4 } }) { ForEach(this.note.tags, (tag: string) { Text(#${tag}) .fontSize(10) .fontColor(#2196F3) .backgroundColor(#E3F2FD) .padding({ left: 6, right: 6, top: 2, bottom: 2 }) .borderRadius(8) }) } Blank() Text(this.formatDate(this.note.updateTime)) .fontSize(10) .fontColor(#999999) } .width(100%) } .padding(16) .backgroundColor(this.note.color) .borderRadius(12) .onClick(() { this.onCardClick?.(); }) } formatDate(timestamp: number): string { let date new Date(timestamp); return ${date.getMonth() 1}/${date.getDate()}; } } // components/CategoryTag.ets Component export struct CategoryTag { private category: Category; private isSelected: boolean; private onSelect?: () void; build() { Row() { Image(this.category.icon) .width(16) .height(16) .margin({ right: 4 }) Text(${this.category.name} (${this.category.count})) .fontSize(14) .fontColor(this.isSelected ? #2196F3 : #666666) } .padding({ left: 12, right: 12, top: 6, bottom: 6 }) .backgroundColor(this.isSelected ? #E3F2FD : #f5f5f5) .borderRadius(20) .onClick(() { this.onSelect?.(); }) } }4.4 主页面实现typescript// pages/Index.ets import { Note, Category } from ../models/NoteModel; import { NoteCard } from ../components/NoteCard; import { SearchBar } from ../components/SearchBar; import { CategoryTag } from ../components/CategoryTag; import { StorageUtil } from ../utils/StorageUtil; Entry Component struct Index { State notes: Note[] []; State filteredNotes: Note[] []; State categories: Category[] []; State selectedCategory: string 全部; State searchText: string ; State showFavoritesOnly: boolean false; State sortType: string 时间降序; private storageUtil: StorageUtil new StorageUtil(); aboutToAppear() { this.loadData(); } loadData() { // 初始化分类 this.categories [ new Category(全部, $r(app.media.all)), new Category(工作, $r(app.media.work)), new Category(学习, $r(app.media.study)), new Category(生活, $r(app.media.life)), new Category(灵感, $r(app.media.idea)) ]; // 加载笔记 let savedNotes this.storageUtil.getNotes(); if (savedNotes savedNotes.length 0) { this.notes savedNotes; } else { // 初始化示例数据 this.initSampleData(); } this.filterNotes(); this.updateCategoryCounts(); } initSampleData() { let note1 new Note(鸿蒙开发学习笔记, 今天学习了ArkTS的基础语法和组件化开发思想收获很多。, 学习); note1.tags [鸿蒙, ArkTS]; let note2 new Note(产品需求会议, 讨论新版本功能点需要增加搜索功能和分类筛选, 工作); note2.tags [会议, 需求]; let note3 new Note(周末计划, 周六爬山周日下午看电影晚上和朋友聚餐, 生活); note3.isFavorite true; this.notes [note1, note2, note3]; this.storageUtil.saveNotes(this.notes); } filterNotes() { let result [...this.notes]; // 分类筛选 if (this.selectedCategory ! 全部) { result result.filter(note note.category this.selectedCategory); } // 收藏筛选 if (this.showFavoritesOnly) { result result.filter(note note.isFavorite); } // 搜索过滤 if (this.searchText.trim() ! ) { let searchLower this.searchText.toLowerCase(); result result.filter(note note.title.toLowerCase().includes(searchLower) || note.content.toLowerCase().includes(searchLower) ); } // 排序 if (this.sortType 时间降序) { result.sort((a, b) b.updateTime - a.updateTime); } else if (this.sortType 时间升序) { result.sort((a, b) a.updateTime - b.updateTime); } else if (this.sortType 标题) { result.sort((a, b) a.title.localeCompare(b.title)); } this.filteredNotes result; } updateCategoryCounts() { this.categories.forEach(cat { if (cat.name 全部) { cat.count this.notes.length; } else { cat.count this.notes.filter(n n.category cat.name).length; } }); } handleSearch(value: string) { this.searchText value; this.filterNotes(); } handleCategorySelect(categoryName: string) { this.selectedCategory categoryName; this.filterNotes(); } handleFavoriteToggle(note: Note) { note.toggleFavorite(); this.storageUtil.saveNotes(this.notes); this.filterNotes(); this.updateCategoryCounts(); } handleNoteClick(note: Note) { // 导航到详情页 router.pushUrl({ url: pages/NoteDetail, params: { noteId: note.id } }); } build() { Column() { // 顶部标题栏 Row() { Text(智能笔记) .fontSize(28) .fontWeight(FontWeight.Bold) Blank() Button({ type: ButtonType.Circle }) { Image($r(app.media.sort)) .width(20) .height(20) } .width(40) .height(40) .backgroundColor(#f0f0f0) .onClick(() { // 显示排序菜单 }) .margin({ right: 8 }) Button({ type: ButtonType.Circle }) { Image($r(app.media.add)) .width(20) .height(20) } .width(40) .height(40) .backgroundColor(#2196F3) .onClick(() { router.pushUrl({ url: pages/NoteEdit }); }) } .padding({ left: 16, right: 16, top: 16, bottom: 8 }) // 搜索栏 SearchBar({ searchText: $searchText, onSearch: this.handleSearch.bind(this) }) .padding({ left: 16, right: 16 }) // 分类标签滚动区 Scroll() { Row({ space: 8 }) { ForEach(this.categories, (category: Category) { CategoryTag({ category: category, isSelected: this.selectedCategory category.name, onSelect: () this.handleCategorySelect(category.name) }) }) } .padding({ left: 16, right: 16 }) } .scrollable(ScrollDirection.Horizontal) .height(50) .margin({ top: 8 }) // 筛选栏 Row() { Row() { Checkbox() .select(this.showFavoritesOnly) .onChange((value: boolean) { this.showFavoritesOnly value; this.filterNotes(); }) Text(仅看收藏) .fontSize(14) .fontColor(#666666) .margin({ left: 4 }) } Blank() Text(共 ${this.filteredNotes.length} 条笔记) .fontSize(14) .fontColor(#999999) } .padding({ left: 16, right: 16, top: 8, bottom: 8 }) // 笔记列表 if (this.filteredNotes.length 0) { List({ space: 12 }) { ForEach(this.filteredNotes, (note: Note) { ListItem() { NoteCard({ note: note, onCardClick: () this.handleNoteClick(note), onFavoriteClick: () this.handleFavoriteToggle(note) }) } .swipeAction({ end: this.buildSwipeMenu(note) }) }) } .layoutWeight(1) .padding({ left: 16, right: 16 }) } else { // 空状态 Column() { Image($r(app.media.empty)) .width(120) .height(120) .margin({ bottom: 16 }) Text(没有找到笔记) .fontSize(16) .fontColor(#999999) Text(点击右上角添加新笔记) .fontSize(14) .fontColor(#cccccc) .margin({ top: 8 }) } .layoutWeight(1) .justifyContent(FlexAlign.Center) } } .width(100%) .height(100%) .backgroundColor(#f8f9fa) } Builder buildSwipeMenu(note: Note) { Row({ space: 2 }) { Button() { Image($r(app.media.delete)) .width(20) .height(20) } .width(50) .height(50) .backgroundColor(#ff4444) .onClick(() { this.deleteNote(note); }) Button() { Image($r(app.media.edit)) .width(20) .height(20) } .width(50) .height(50) .backgroundColor(#2196F3) .onClick(() { router.pushUrl({ url: pages/NoteEdit, params: { noteId: note.id } }); }) } } deleteNote(note: Note) { let index this.notes.findIndex(n n.id note.id); if (index ! -1) { this.notes.splice(index, 1); this.storageUtil.saveNotes(this.notes); this.filterNotes(); this.updateCategoryCounts(); } } }4.5 笔记编辑页面typescript// pages/NoteEdit.ets import { Note } from ../models/NoteModel; import { StorageUtil } from ../utils/StorageUtil; Entry Component struct NoteEdit { State note: Note new Note(, ); State title: string ; State content: string ; State selectedCategory: string 默认; State categories: string[] [默认, 工作, 学习, 生活, 灵感]; State tagInput: string ; State tags: string[] []; private noteId?: string; private storageUtil: StorageUtil new StorageUtil(); aboutToAppear() { // 获取路由参数 const params router.getParams() as { noteId?: string }; if (params?.noteId) { this.noteId params.noteId; this.loadNote(); } else { // 新建笔记 this.note new Note(, ); } } loadNote() { let notes this.storageUtil.getNotes(); let found notes.find(n n.id this.noteId); if (found) { this.note found; this.title this.note.title; this.content this.note.content; this.selectedCategory this.note.category; this.tags [...this.note.tags]; } } saveNote() { if (!this.title.trim()) { // 标题不能为空提示 return; } if (this.noteId) { // 更新 this.note.title this.title; this.note.content this.content; this.note.category this.selectedCategory; this.note.tags [...this.tags]; this.note.updateTime Date.now(); } else { // 新建 this.note new Note(this.title, this.content, this.selectedCategory); this.note.tags [...this.tags]; } let notes this.storageUtil.getNotes(); if (this.noteId) { let index notes.findIndex(n n.id this.noteId); if (index ! -1) { notes[index] this.note; } } else { notes.push(this.note); } this.storageUtil.saveNotes(notes); router.back(); } addTag() { if (this.tagInput.trim() !this.tags.includes(this.tagInput.trim())) { this.tags.push(this.tagInput.trim()); this.tagInput ; } } removeTag(index: number) { this.tags.splice(index, 1); } build() { Column() { // 顶部工具栏 Row() { Button({ type: ButtonType.Circle }) { Image($r(app.media.back)) .width(20) .height(20) } .width(40) .height(40) .backgroundColor(#f0f0f0) .onClick(() { router.back(); }) Blank() Button(保存) .backgroundColor(#2196F3) .onClick(() { this.saveNote(); }) } .padding(16) Scroll() { Column({ space: 20 }) { // 标题输入 TextInput({ placeholder: 标题, text: this.title }) .height(50) .fontSize(20) .fontWeight(FontWeight.Bold) .padding({ left: 16, right: 16 }) .onChange((value: string) { this.title value; }) // 分类选择 Row() { Text(分类:).fontSize(16).fontColor(#666666) Scroll() { Row({ space: 8 }) { ForEach(this.categories, (cat: string) { Text(cat) .padding({ left: 12, right: 12, top: 6, bottom: 6 }) .backgroundColor(this.selectedCategory cat ? #2196F3 : #f0f0f0) .fontColor(this.selectedCategory cat ? Color.White : #666666) .borderRadius(16) .onClick(() { this.selectedCategory cat; }) }) } } .scrollable(ScrollDirection.Horizontal) .layoutWeight(1) } .padding({ left: 16, right: 16 }) // 标签管理 Column() { Row() { TextInput({ placeholder: 添加标签, text: this.tagInput }) .height(40) .layoutWeight(1) .onChange((value: string) { this.tagInput value; }) .onSubmit(() { this.addTag(); }) Button(添加) .height(40) .margin({ left: 8 }) .onClick(() { this.addTag(); }) } Flex({ wrap: FlexWrap.Wrap, space: { left: 8, top: 8 } }) { ForEach(this.tags, (tag: string, index: number) { Row() { Text(#${tag}) .fontSize(14) .fontColor(#2196F3) .margin({ right: 4 }) Image($r(app.media.close)) .width(12) .height(12) .onClick(() { this.removeTag(index); }) } .padding({ left: 8, right: 8, top: 4, bottom: 4 }) .backgroundColor(#E3F2FD) .borderRadius(16) .margin({ right: 8, bottom: 8 }) }) } .margin({ top: 8 }) } .padding({ left: 16, right: 16 }) // 内容输入 TextArea({ placeholder: 开始记录..., text: this.content }) .height(300) .fontSize(16) .padding(16) .backgroundColor(#fafafa) .onChange((value: string) { this.content value; }) } } .layoutWeight(1) } .width(100%) .height(100%) .backgroundColor(Color.White) } }4.6 数据存储工具类typescript// utils/StorageUtil.ets import { Note } from ../models/NoteModel; import preferences from ohos.data.preferences; export class StorageUtil { private static readonly NOTES_KEY smart_notes; private preferences: preferences.Preferences | null null; constructor() { this.initPreferences(); } async initPreferences() { try { this.preferences await preferences.getPreferences(getContext(), notes_preferences); } catch (error) { console.error(初始化Preferences失败, error); } } async saveNotes(notes: Note[]): Promiseboolean { try { if (!this.preferences) { await this.initPreferences(); } // 将Note对象转换为可存储的JSON let notesJson notes.map(note ({ id: note.id, title: note.title, content: note.content, category: note.category, tags: note.tags, createTime: note.createTime, updateTime: note.updateTime, isFavorite: note.isFavorite, color: note.color })); await this.preferences?.put(StorageUtil.NOTES_KEY, JSON.stringify(notesJson)); await this.preferences?.flush(); return true; } catch (error) { console.error(保存笔记失败, error); return false; } } getNotes(): Note[] { // 简化版实际应用中需要异步处理 // 此处仅为示例 return []; } }五、性能优化与最佳实践5.1 渲染性能优化使用LazyForEach代替ForEach处理长列表时使用LazyForEach实现懒加载。typescript// 使用LazyForEach优化长列表 class NoteDataSource extends BasicDataSourceNote { // 实现数据源方法 } LazyForEach(this.dataSource, (note: Note) { ListItem() { NoteCard({ note: note }) } }, (note: Note) note.id)避免不必要的状态更新最小化状态变量范围只将需要驱动UI的变量定义为State。typescript// 反例 State fullData: ComplexData; // 包含大量不需要触发UI更新的数据 // 正例 State uiState: UIState; // 仅包含与UI相关的状态 private internalData: ComplexData; // 业务数据使用taskpool处理耗时操作避免阻塞UI线程。typescriptimport taskpool from ohos.taskpool; Concurrent async function processNotes(notes: Note[]): PromiseNote[] { // 耗时处理逻辑 return processedNotes; } async handleData() { let task new taskpool.Task(processNotes, this.notes); let result await taskpool.execute(task); this.notes result; }5.2 组件设计原则单一职责原则每个组件只负责一个功能领域。接口清晰组件对外暴露的属性和事件要明确。typescriptComponent export interface UserProfileProps { userId: string; onProfileClick?: (id: string) void; editable?: boolean; }状态提升共享状态提升到共同的父组件管理。5.3 内存管理及时释放资源在aboutToDisappear中清理定时器、取消订阅。typescriptComponent struct TimerComponent { private timer: number -1; aboutToAppear() { this.timer setInterval(() { // 定时任务 }, 1000); } aboutToDisappear() { clearInterval(this.timer); } }避免循环引用注意闭包中的this引用。六、多端部署与自适应布局6.1 响应式布局使用百分比、Grid布局等实现不同屏幕尺寸适配。typescriptComponent struct ResponsiveLayout { State currentBreakpoint: string sm; aboutToAppear() { this.updateBreakpoint(); window.on(sizeChange, () this.updateBreakpoint()); } updateBreakpoint() { let width window.getWindowWidth(); if (width 520) this.currentBreakpoint sm; else if (width 840) this.currentBreakpoint md; else this.currentBreakpoint lg; } build() { Grid() { if (this.currentBreakpoint lg) { // 大屏三列布局 GridItem() { /* 内容 */ } GridItem() { /* 内容 */ } GridItem() { /* 内容 */ } } else if (this.currentBreakpoint md) { // 中屏两列布局 GridItem() { /* 内容 */ } GridItem() { /* 内容 */ } } else { // 小屏单列布局 GridItem() { /* 内容 */ } } } } }6.2 原子化服务卡片开发服务卡片实现快速信息展示。typescript// form/NoteWidget.ets Entry Component struct NoteWidget { Prop latestNote: string; build() { Column() { Text(最新笔记) .fontSize(12) .fontColor(#666666) Text(this.latestNote) .fontSize(16) .fontWeight(FontWeight.Bold) .maxLines(2) .textOverflow({ overflow: TextOverflow.Ellipsis }) .margin({ top: 4 }) Button(快速记录) .width(100%) .height(30) .fontSize(12) .margin({ top: 8 }) } .padding(12) .width(100%) .height(100%) .backgroundColor(#FFFFFF) } }
鸿蒙 HarmonyOS NEXT星河版APP应用开发-ArkTS面向对象及组件化UI开发应用实例
概述HarmonyOS NEXT鸿蒙星河版作为华为打造的纯血鸿蒙系统其应用开发体系基于ArkTS语言和ArkUI框架。ArkTS在TypeScript基础上扩展了声明式UI、状态管理等特性而组件化开发则是构建复杂应用的核心思想。本文将从面向对象基础到组件化UI实践通过完整实例详解鸿蒙NEXT应用开发全流程。一、ArkTS面向对象基础1.1 类与对象ArkTS作为鸿蒙生态的主力开发语言在TypeScript基础上扩展了声明式UI能力同时完整支持面向对象编程范式。类的定义类是用于创建对象的模板同时类声明也会引入一个新类型可定义其实例属性、方法和构造函数。typescript// 定义一个Person类 class Person { // 属性声明 name: string; age: number; // 构造函数 constructor(name: string, age: number) { this.name name; this.age age; } // 方法定义 introduce(): string { return 我叫${this.name}今年${this.age}岁; } } // 创建对象实例 let person new Person(张三, 25); console.log(person.introduce());1.2 访问修饰符与继承ArkTS支持public、private、protected等访问修饰符以及类的继承机制。typescript// 基类 class Animal { protected name: string; constructor(name: string) { this.name name; } makeSound(): void { console.log(${this.name}发出声音); } } // 派生类 class Dog extends Animal { private breed: string; // 品种私有属性 constructor(name: string, breed: string) { super(name); // 调用父类构造函数 this.breed breed; } // 方法重写 makeSound(): void { console.log(${this.name}${this.breed}汪汪叫); } // 特有方法 fetch(): void { console.log(${this.name}在接飞盘); } } let dog new Dog(旺财, 金毛); dog.makeSound(); // 输出旺财金毛汪汪叫 dog.fetch(); // 输出旺财在接飞盘1.3 接口与类型别名接口用于定义对象的结构和契约是实现组件间解耦的重要工具。typescript// 定义用户接口 interface User { id: number; name: string; email?: string; // 可选属性 readonly createdAt: Date; // 只读属性 } // 实现接口 class Member implements User { id: number; name: string; email?: string; readonly createdAt: Date; constructor(id: number, name: string, email?: string) { this.id id; this.name name; this.email email; this.createdAt new Date(); } } // 函数接口 interface SearchFunc { (source: string, subString: string): boolean; } let mySearch: SearchFunc function(src: string, sub: string): boolean { return src.includes(sub); };1.4 装饰器ArkTS大量使用装饰器来实现声明式UI和状态管理这是其核心特性之一。typescript// 类装饰器 function sealed(constructor: Function) { Object.seal(constructor); Object.seal(constructor.prototype); } sealed class Greeter { greeting: string; constructor(message: string) { this.greeting message; } greet() { return Hello, ${this.greeting}; } }二、ArkTS组件化UI开发2.1 声明式UI基础ArkUI方舟开发框架提供基于ArkTS的声明式开发范式通过简洁的语法描述UI状态和结构。核心概念Component装饰struct使其具有组件化能力Entry标记页面入口组件build函数定义组件的UI描述typescriptEntry Component struct HelloComponent { State message: string Hello, HarmonyOS NEXT!; build() { Row() { Column() { Text(this.message) .fontSize(50) .fontWeight(FontWeight.Bold) .fontColor(Color.Blue) } .width(100%) } .height(100%) } }2.2 自定义组件创建自定义组件是UI复用的基本单位通过Component装饰器定义。typescript// 定义可复用的卡片组件 Component struct InfoCard { // 组件属性 private title: string ; private content: string ; private cardWidth: Length 300; build() { Column() { Text(this.title) .fontSize(20) .fontWeight(FontWeight.Bold) .width(100%) .textAlign(TextAlign.Center) .padding(10) .backgroundColor(#f0f0f0) Text(this.content) .fontSize(16) .padding(15) .width(100%) } .width(this.cardWidth) .borderRadius(10) .backgroundColor(Color.White) .shadow({ radius: 10, color: #888888 }) } } // 使用自定义组件 Entry Component struct CardDemo { build() { Column({ space: 20 }) { InfoCard({ title: 鸿蒙特性, content: 一次开发多端部署可分可合自由流转 }) InfoCard({ title: ArkTS优势, content: 声明式UI、状态管理、跨端能力, cardWidth: 350 }) } .width(100%) .padding(20) } }2.3 布局与容器组件ArkUI提供多种布局容器实现灵活的界面排列。typescriptEntry Component struct LayoutDemo { build() { // 线性布局 Column({ space: 15 }) { Text(线性布局示例).fontSize(24).fontWeight(FontWeight.Bold) // Row水平布局 Row({ space: 10 }) { Text(左).backgroundColor(#ff6b6b).padding(15) Text(中).backgroundColor(#4ecdc4).padding(15) Text(右).backgroundColor(#ffe66d).padding(15) } .width(100%) .justifyContent(FlexAlign.SpaceAround) Divider() // 层叠布局 Stack({ alignContent: Alignment.BottomEnd }) { Image($r(app.media.background)) .width(300) .height(200) .objectFit(ImageFit.Cover) Text(底部文字) .backgroundColor(rgba(0,0,0,0.5)) .fontColor(Color.White) .padding(8) } .borderRadius(10) .margin({ top: 20 }) // 弹性布局 Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap, justifyContent: FlexAlign.SpaceBetween }) { ForEach(1 to 6, (item: number) { Text(项目${item}) .width(80) .height(80) .backgroundColor(#3498db) .fontColor(Color.White) .textAlign(TextAlign.Center) .borderRadius(8) .margin(5) }) } } .padding(20) .width(100%) } }三、状态管理深入3.1 组件内状态StateState装饰的变量是组件内部状态数据修改时会触发UI重新渲染。typescriptEntry Component struct CounterDemo { State count: number 0; State isActive: boolean false; build() { Column({ space: 20 }) { Text(当前计数: ${this.count}) .fontSize(30) .fontColor(this.isActive ? Color.Green : Color.Red) Row({ space: 15 }) { Button(增加) .onClick(() { this.count; if (this.count 10) this.isActive true; }) Button(减少) .onClick(() { this.count--; if (this.count 0) this.isActive false; }) Button(重置) .onClick(() { this.count 0; this.isActive false; }) } Text(this.isActive ? 活跃状态 : 非活跃状态) .fontSize(16) .fontColor(this.isActive ? Color.Green : Color.Gray) } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }3.2 父子组件通信Prop与LinkProp单向数据同步子组件接收父组件数据但不能修改。Link双向数据同步父子组件数据变更互相影响。typescript// 子组件 - 使用Prop单向接收 Component struct PropChild { Prop count: number; Prop title: string; build() { Column() { Text(this.title).fontSize(18).fontWeight(FontWeight.Bold) Text(Prop接收值: ${this.count}).fontSize(20).fontColor(Color.Blue) Button(尝试修改(无效)) .onClick(() { // this.count; // 错误Prop不允许修改 console.log(Prop不能直接修改); }) } .padding(15) .backgroundColor(#f8f9fa) .borderRadius(8) } } // 子组件 - 使用Link双向绑定 Component struct LinkChild { Link count: number; build() { Row({ space: 10 }) { Text(Link值: ${this.count}).fontSize(20) Button() .onClick(() this.count) Button(-) .onClick(() this.count--) } .padding(15) .backgroundColor(#e9ecef) .borderRadius(8) } } // 父组件 Entry Component struct ParentComponent { State parentCount: number 10; build() { Column({ space: 20 }) { Text(父组件状态: ${this.parentCount}) .fontSize(24) .fontWeight(FontWeight.Bold) PropChild({ count: this.parentCount, title: Prop示例 }) // 使用$符号创建Link双向绑定 LinkChild({ count: $parentCount }) Button(父组件增加) .onClick(() this.parentCount) } .padding(20) .width(100%) } }3.3 跨级组件通信Provide与ConsumeProvide和Consume实现祖先组件与后代组件之间的数据传递避免逐层传递。typescript// 祖先组件 Component struct GrandParent { Provide userInfo: string 初始用户; Provide theme: string light; build() { Column({ space: 20 }) { Text(祖父组件).fontSize(24) Text(当前用户: ${this.userInfo}) Button(切换主题) .onClick(() { this.theme this.theme light ? dark : light; }) Parent() } .padding(20) .width(100%) } } // 中间组件无需关心数据 Component struct Parent { build() { Column() { Text(父组件(中间层)) .fontSize(18) .fontColor(Color.Gray) Child() } .padding(10) } } // 后代组件 Component struct Child { Consume userInfo: string; Consume theme: string; build() { Column({ space: 15 }) { Text(孙组件).fontSize(20).fontWeight(FontWeight.Bold) Row() { Text(接收用户: ${this.userInfo}) Button(修改用户) .onClick(() { this.userInfo 新用户_ Math.floor(Math.random() * 100); }) } Text(当前主题: ${this.theme}) .fontColor(this.theme dark ? Color.Black : Color.Blue) } .padding(15) .backgroundColor(this.theme dark ? #333 : #f0f0f0) .borderRadius(8) } } Entry Component struct ProvideConsumeDemo { build() { GrandParent() } }3.4 对象状态管理Observed与ObjectLink对于嵌套对象需要使用Observed装饰类ObjectLink装饰对象属性。typescript// 被观察的类 Observed class Task { name: string; completed: boolean; subtasks: SubTask[]; constructor(name: string) { this.name name; this.completed false; this.subtasks []; } } Observed class SubTask { title: string; done: boolean; constructor(title: string) { this.title title; this.done false; } } Component struct SubTaskItem { ObjectLink subTask: SubTask; build() { Row({ space: 10 }) { Checkbox() .select(this.subTask.done) .onChange((value: boolean) { this.subTask.done value; }) Text(this.subTask.title) .decoration({ type: this.subTask.done ? TextDecorationType.LineThrough : TextDecorationType.None }) } .padding(5) } } Component struct TaskItem { ObjectLink task: Task; build() { Column() { Row({ space: 10 }) { Checkbox() .select(this.task.completed) .onChange((value: boolean) { this.task.completed value; }) Text(this.task.name) .fontSize(18) .fontWeight(FontWeight.Bold) } Column() { ForEach(this.task.subtasks, (sub: SubTask) { SubTaskItem({ subTask: sub }) }) } .padding({ left: 30 }) } .padding(10) .backgroundColor(#fafafa) .borderRadius(8) } } Entry Component struct TaskManager { State tasks: Task[] []; aboutToAppear() { let task1 new Task(学习鸿蒙); task1.subtasks.push(new SubTask(看文档)); task1.subtasks.push(new SubTask(写代码)); task1.subtasks.push(new SubTask(做测试)); let task2 new Task(项目开发); task2.subtasks.push(new SubTask(需求分析)); task2.subtasks.push(new SubTask(设计)); this.tasks [task1, task2]; } build() { Column({ space: 15 }) { Text(任务列表).fontSize(24).fontWeight(FontWeight.Bold) ForEach(this.tasks, (task: Task) { TaskItem({ task: task }) }) Button(添加子任务) .onClick(() { if (this.tasks.length 0) { this.tasks[0].subtasks.push(new SubTask(新子任务)); } }) } .padding(20) .width(100%) } }四、综合应用实例智能笔记应用通过一个完整的智能笔记应用综合运用ArkTS面向对象特性和组件化UI开发能力。4.1 项目结构设计text├── entry │ ├── src/main/ets │ │ ├── entryability │ │ │ └── EntryAbility.ets │ │ ├── pages │ │ │ ├── Index.ets │ │ │ ├── NoteDetail.ets │ │ │ └── NoteEdit.ets │ │ ├── components │ │ │ ├── NoteCard.ets │ │ │ ├── SearchBar.ets │ │ │ └── CategoryTag.ets │ │ ├── models │ │ │ └── NoteModel.ets │ │ └── utils │ │ └── StorageUtil.ets │ └── module.json54.2 数据模型定义typescript// models/NoteModel.ets Observed export class Note { id: string; title: string; content: string; category: string; tags: string[]; createTime: number; updateTime: number; isFavorite: boolean; color: string; constructor(title: string, content: string, category: string 默认) { this.id Date.now().toString() Math.random().toString(36).substr(2, 9); this.title title; this.content content; this.category category; this.tags []; this.createTime Date.now(); this.updateTime Date.now(); this.isFavorite false; this.color this.getRandomColor(); } private getRandomColor(): string { const colors [#FFCDD2, #F8BBD9, #E1BEE7, #D1C4E9, #C5CAE9, #BBDEFB, #B3E5FC, #B2EBF2, #B2DFDB, #C8E6C9]; return colors[Math.floor(Math.random() * colors.length)]; } updateContent(content: string) { this.content content; this.updateTime Date.now(); } toggleFavorite() { this.isFavorite !this.isFavorite; } } // 笔记分类 export class Category { name: string; count: number; icon: Resource; constructor(name: string, icon: Resource) { this.name name; this.count 0; this.icon icon; } }4.3 可复用组件开发typescript// components/SearchBar.ets Component export struct SearchBar { Link searchText: string; State isFocused: boolean false; private onSearch?: (value: string) void; build() { Row() { Image($r(app.media.search)) .width(20) .height(20) .margin({ left: 12, right: 8 }) TextInput({ placeholder: 搜索笔记..., text: this.searchText }) .height(40) .backgroundColor(Color.Transparent) .onChange((value: string) { this.searchText value; this.onSearch?.(value); }) .onFocus(() { this.isFocused true; }) .onBlur(() { this.isFocused false; }) if (this.searchText.length 0) { Button({ type: ButtonType.Circle }) { Image($r(app.media.close)) .width(16) .height(16) } .width(30) .height(30) .backgroundColor(#cccccc) .onClick(() { this.searchText ; this.onSearch?.(); }) .margin({ right: 8 }) } } .width(100%) .height(50) .backgroundColor(this.isFocused ? #f0f0f0 : #f5f5f5) .borderRadius(25) .padding({ right: 8 }) } } // components/NoteCard.ets Component export struct NoteCard { ObjectLink note: Note; private onCardClick?: () void; private onFavoriteClick?: () void; build() { Column() { Row() { // 分类标签 Text(this.note.category) .fontSize(12) .fontColor(#666666) .backgroundColor(#e0e0e0) .padding({ left: 8, right: 8, top: 2, bottom: 2 }) .borderRadius(10) Blank() // 收藏按钮 Image(this.note.isFavorite ? $r(app.media.favorite_filled) : $r(app.media.favorite)) .width(20) .height(20) .onClick((event) { event.stopPropagation(); this.onFavoriteClick?.(); }) } .width(100%) Text(this.note.title) .fontSize(18) .fontWeight(FontWeight.Bold) .width(100%) .maxLines(1) .textOverflow({ overflow: TextOverflow.Ellipsis }) .margin({ top: 8, bottom: 4 }) Text(this.note.content) .fontSize(14) .fontColor(#666666) .width(100%) .maxLines(2) .textOverflow({ overflow: TextOverflow.Ellipsis }) .margin({ bottom: 8 }) Row() { // 标签列表 Flex({ wrap: FlexWrap.Wrap, space: { left: 4, right: 4 } }) { ForEach(this.note.tags, (tag: string) { Text(#${tag}) .fontSize(10) .fontColor(#2196F3) .backgroundColor(#E3F2FD) .padding({ left: 6, right: 6, top: 2, bottom: 2 }) .borderRadius(8) }) } Blank() Text(this.formatDate(this.note.updateTime)) .fontSize(10) .fontColor(#999999) } .width(100%) } .padding(16) .backgroundColor(this.note.color) .borderRadius(12) .onClick(() { this.onCardClick?.(); }) } formatDate(timestamp: number): string { let date new Date(timestamp); return ${date.getMonth() 1}/${date.getDate()}; } } // components/CategoryTag.ets Component export struct CategoryTag { private category: Category; private isSelected: boolean; private onSelect?: () void; build() { Row() { Image(this.category.icon) .width(16) .height(16) .margin({ right: 4 }) Text(${this.category.name} (${this.category.count})) .fontSize(14) .fontColor(this.isSelected ? #2196F3 : #666666) } .padding({ left: 12, right: 12, top: 6, bottom: 6 }) .backgroundColor(this.isSelected ? #E3F2FD : #f5f5f5) .borderRadius(20) .onClick(() { this.onSelect?.(); }) } }4.4 主页面实现typescript// pages/Index.ets import { Note, Category } from ../models/NoteModel; import { NoteCard } from ../components/NoteCard; import { SearchBar } from ../components/SearchBar; import { CategoryTag } from ../components/CategoryTag; import { StorageUtil } from ../utils/StorageUtil; Entry Component struct Index { State notes: Note[] []; State filteredNotes: Note[] []; State categories: Category[] []; State selectedCategory: string 全部; State searchText: string ; State showFavoritesOnly: boolean false; State sortType: string 时间降序; private storageUtil: StorageUtil new StorageUtil(); aboutToAppear() { this.loadData(); } loadData() { // 初始化分类 this.categories [ new Category(全部, $r(app.media.all)), new Category(工作, $r(app.media.work)), new Category(学习, $r(app.media.study)), new Category(生活, $r(app.media.life)), new Category(灵感, $r(app.media.idea)) ]; // 加载笔记 let savedNotes this.storageUtil.getNotes(); if (savedNotes savedNotes.length 0) { this.notes savedNotes; } else { // 初始化示例数据 this.initSampleData(); } this.filterNotes(); this.updateCategoryCounts(); } initSampleData() { let note1 new Note(鸿蒙开发学习笔记, 今天学习了ArkTS的基础语法和组件化开发思想收获很多。, 学习); note1.tags [鸿蒙, ArkTS]; let note2 new Note(产品需求会议, 讨论新版本功能点需要增加搜索功能和分类筛选, 工作); note2.tags [会议, 需求]; let note3 new Note(周末计划, 周六爬山周日下午看电影晚上和朋友聚餐, 生活); note3.isFavorite true; this.notes [note1, note2, note3]; this.storageUtil.saveNotes(this.notes); } filterNotes() { let result [...this.notes]; // 分类筛选 if (this.selectedCategory ! 全部) { result result.filter(note note.category this.selectedCategory); } // 收藏筛选 if (this.showFavoritesOnly) { result result.filter(note note.isFavorite); } // 搜索过滤 if (this.searchText.trim() ! ) { let searchLower this.searchText.toLowerCase(); result result.filter(note note.title.toLowerCase().includes(searchLower) || note.content.toLowerCase().includes(searchLower) ); } // 排序 if (this.sortType 时间降序) { result.sort((a, b) b.updateTime - a.updateTime); } else if (this.sortType 时间升序) { result.sort((a, b) a.updateTime - b.updateTime); } else if (this.sortType 标题) { result.sort((a, b) a.title.localeCompare(b.title)); } this.filteredNotes result; } updateCategoryCounts() { this.categories.forEach(cat { if (cat.name 全部) { cat.count this.notes.length; } else { cat.count this.notes.filter(n n.category cat.name).length; } }); } handleSearch(value: string) { this.searchText value; this.filterNotes(); } handleCategorySelect(categoryName: string) { this.selectedCategory categoryName; this.filterNotes(); } handleFavoriteToggle(note: Note) { note.toggleFavorite(); this.storageUtil.saveNotes(this.notes); this.filterNotes(); this.updateCategoryCounts(); } handleNoteClick(note: Note) { // 导航到详情页 router.pushUrl({ url: pages/NoteDetail, params: { noteId: note.id } }); } build() { Column() { // 顶部标题栏 Row() { Text(智能笔记) .fontSize(28) .fontWeight(FontWeight.Bold) Blank() Button({ type: ButtonType.Circle }) { Image($r(app.media.sort)) .width(20) .height(20) } .width(40) .height(40) .backgroundColor(#f0f0f0) .onClick(() { // 显示排序菜单 }) .margin({ right: 8 }) Button({ type: ButtonType.Circle }) { Image($r(app.media.add)) .width(20) .height(20) } .width(40) .height(40) .backgroundColor(#2196F3) .onClick(() { router.pushUrl({ url: pages/NoteEdit }); }) } .padding({ left: 16, right: 16, top: 16, bottom: 8 }) // 搜索栏 SearchBar({ searchText: $searchText, onSearch: this.handleSearch.bind(this) }) .padding({ left: 16, right: 16 }) // 分类标签滚动区 Scroll() { Row({ space: 8 }) { ForEach(this.categories, (category: Category) { CategoryTag({ category: category, isSelected: this.selectedCategory category.name, onSelect: () this.handleCategorySelect(category.name) }) }) } .padding({ left: 16, right: 16 }) } .scrollable(ScrollDirection.Horizontal) .height(50) .margin({ top: 8 }) // 筛选栏 Row() { Row() { Checkbox() .select(this.showFavoritesOnly) .onChange((value: boolean) { this.showFavoritesOnly value; this.filterNotes(); }) Text(仅看收藏) .fontSize(14) .fontColor(#666666) .margin({ left: 4 }) } Blank() Text(共 ${this.filteredNotes.length} 条笔记) .fontSize(14) .fontColor(#999999) } .padding({ left: 16, right: 16, top: 8, bottom: 8 }) // 笔记列表 if (this.filteredNotes.length 0) { List({ space: 12 }) { ForEach(this.filteredNotes, (note: Note) { ListItem() { NoteCard({ note: note, onCardClick: () this.handleNoteClick(note), onFavoriteClick: () this.handleFavoriteToggle(note) }) } .swipeAction({ end: this.buildSwipeMenu(note) }) }) } .layoutWeight(1) .padding({ left: 16, right: 16 }) } else { // 空状态 Column() { Image($r(app.media.empty)) .width(120) .height(120) .margin({ bottom: 16 }) Text(没有找到笔记) .fontSize(16) .fontColor(#999999) Text(点击右上角添加新笔记) .fontSize(14) .fontColor(#cccccc) .margin({ top: 8 }) } .layoutWeight(1) .justifyContent(FlexAlign.Center) } } .width(100%) .height(100%) .backgroundColor(#f8f9fa) } Builder buildSwipeMenu(note: Note) { Row({ space: 2 }) { Button() { Image($r(app.media.delete)) .width(20) .height(20) } .width(50) .height(50) .backgroundColor(#ff4444) .onClick(() { this.deleteNote(note); }) Button() { Image($r(app.media.edit)) .width(20) .height(20) } .width(50) .height(50) .backgroundColor(#2196F3) .onClick(() { router.pushUrl({ url: pages/NoteEdit, params: { noteId: note.id } }); }) } } deleteNote(note: Note) { let index this.notes.findIndex(n n.id note.id); if (index ! -1) { this.notes.splice(index, 1); this.storageUtil.saveNotes(this.notes); this.filterNotes(); this.updateCategoryCounts(); } } }4.5 笔记编辑页面typescript// pages/NoteEdit.ets import { Note } from ../models/NoteModel; import { StorageUtil } from ../utils/StorageUtil; Entry Component struct NoteEdit { State note: Note new Note(, ); State title: string ; State content: string ; State selectedCategory: string 默认; State categories: string[] [默认, 工作, 学习, 生活, 灵感]; State tagInput: string ; State tags: string[] []; private noteId?: string; private storageUtil: StorageUtil new StorageUtil(); aboutToAppear() { // 获取路由参数 const params router.getParams() as { noteId?: string }; if (params?.noteId) { this.noteId params.noteId; this.loadNote(); } else { // 新建笔记 this.note new Note(, ); } } loadNote() { let notes this.storageUtil.getNotes(); let found notes.find(n n.id this.noteId); if (found) { this.note found; this.title this.note.title; this.content this.note.content; this.selectedCategory this.note.category; this.tags [...this.note.tags]; } } saveNote() { if (!this.title.trim()) { // 标题不能为空提示 return; } if (this.noteId) { // 更新 this.note.title this.title; this.note.content this.content; this.note.category this.selectedCategory; this.note.tags [...this.tags]; this.note.updateTime Date.now(); } else { // 新建 this.note new Note(this.title, this.content, this.selectedCategory); this.note.tags [...this.tags]; } let notes this.storageUtil.getNotes(); if (this.noteId) { let index notes.findIndex(n n.id this.noteId); if (index ! -1) { notes[index] this.note; } } else { notes.push(this.note); } this.storageUtil.saveNotes(notes); router.back(); } addTag() { if (this.tagInput.trim() !this.tags.includes(this.tagInput.trim())) { this.tags.push(this.tagInput.trim()); this.tagInput ; } } removeTag(index: number) { this.tags.splice(index, 1); } build() { Column() { // 顶部工具栏 Row() { Button({ type: ButtonType.Circle }) { Image($r(app.media.back)) .width(20) .height(20) } .width(40) .height(40) .backgroundColor(#f0f0f0) .onClick(() { router.back(); }) Blank() Button(保存) .backgroundColor(#2196F3) .onClick(() { this.saveNote(); }) } .padding(16) Scroll() { Column({ space: 20 }) { // 标题输入 TextInput({ placeholder: 标题, text: this.title }) .height(50) .fontSize(20) .fontWeight(FontWeight.Bold) .padding({ left: 16, right: 16 }) .onChange((value: string) { this.title value; }) // 分类选择 Row() { Text(分类:).fontSize(16).fontColor(#666666) Scroll() { Row({ space: 8 }) { ForEach(this.categories, (cat: string) { Text(cat) .padding({ left: 12, right: 12, top: 6, bottom: 6 }) .backgroundColor(this.selectedCategory cat ? #2196F3 : #f0f0f0) .fontColor(this.selectedCategory cat ? Color.White : #666666) .borderRadius(16) .onClick(() { this.selectedCategory cat; }) }) } } .scrollable(ScrollDirection.Horizontal) .layoutWeight(1) } .padding({ left: 16, right: 16 }) // 标签管理 Column() { Row() { TextInput({ placeholder: 添加标签, text: this.tagInput }) .height(40) .layoutWeight(1) .onChange((value: string) { this.tagInput value; }) .onSubmit(() { this.addTag(); }) Button(添加) .height(40) .margin({ left: 8 }) .onClick(() { this.addTag(); }) } Flex({ wrap: FlexWrap.Wrap, space: { left: 8, top: 8 } }) { ForEach(this.tags, (tag: string, index: number) { Row() { Text(#${tag}) .fontSize(14) .fontColor(#2196F3) .margin({ right: 4 }) Image($r(app.media.close)) .width(12) .height(12) .onClick(() { this.removeTag(index); }) } .padding({ left: 8, right: 8, top: 4, bottom: 4 }) .backgroundColor(#E3F2FD) .borderRadius(16) .margin({ right: 8, bottom: 8 }) }) } .margin({ top: 8 }) } .padding({ left: 16, right: 16 }) // 内容输入 TextArea({ placeholder: 开始记录..., text: this.content }) .height(300) .fontSize(16) .padding(16) .backgroundColor(#fafafa) .onChange((value: string) { this.content value; }) } } .layoutWeight(1) } .width(100%) .height(100%) .backgroundColor(Color.White) } }4.6 数据存储工具类typescript// utils/StorageUtil.ets import { Note } from ../models/NoteModel; import preferences from ohos.data.preferences; export class StorageUtil { private static readonly NOTES_KEY smart_notes; private preferences: preferences.Preferences | null null; constructor() { this.initPreferences(); } async initPreferences() { try { this.preferences await preferences.getPreferences(getContext(), notes_preferences); } catch (error) { console.error(初始化Preferences失败, error); } } async saveNotes(notes: Note[]): Promiseboolean { try { if (!this.preferences) { await this.initPreferences(); } // 将Note对象转换为可存储的JSON let notesJson notes.map(note ({ id: note.id, title: note.title, content: note.content, category: note.category, tags: note.tags, createTime: note.createTime, updateTime: note.updateTime, isFavorite: note.isFavorite, color: note.color })); await this.preferences?.put(StorageUtil.NOTES_KEY, JSON.stringify(notesJson)); await this.preferences?.flush(); return true; } catch (error) { console.error(保存笔记失败, error); return false; } } getNotes(): Note[] { // 简化版实际应用中需要异步处理 // 此处仅为示例 return []; } }五、性能优化与最佳实践5.1 渲染性能优化使用LazyForEach代替ForEach处理长列表时使用LazyForEach实现懒加载。typescript// 使用LazyForEach优化长列表 class NoteDataSource extends BasicDataSourceNote { // 实现数据源方法 } LazyForEach(this.dataSource, (note: Note) { ListItem() { NoteCard({ note: note }) } }, (note: Note) note.id)避免不必要的状态更新最小化状态变量范围只将需要驱动UI的变量定义为State。typescript// 反例 State fullData: ComplexData; // 包含大量不需要触发UI更新的数据 // 正例 State uiState: UIState; // 仅包含与UI相关的状态 private internalData: ComplexData; // 业务数据使用taskpool处理耗时操作避免阻塞UI线程。typescriptimport taskpool from ohos.taskpool; Concurrent async function processNotes(notes: Note[]): PromiseNote[] { // 耗时处理逻辑 return processedNotes; } async handleData() { let task new taskpool.Task(processNotes, this.notes); let result await taskpool.execute(task); this.notes result; }5.2 组件设计原则单一职责原则每个组件只负责一个功能领域。接口清晰组件对外暴露的属性和事件要明确。typescriptComponent export interface UserProfileProps { userId: string; onProfileClick?: (id: string) void; editable?: boolean; }状态提升共享状态提升到共同的父组件管理。5.3 内存管理及时释放资源在aboutToDisappear中清理定时器、取消订阅。typescriptComponent struct TimerComponent { private timer: number -1; aboutToAppear() { this.timer setInterval(() { // 定时任务 }, 1000); } aboutToDisappear() { clearInterval(this.timer); } }避免循环引用注意闭包中的this引用。六、多端部署与自适应布局6.1 响应式布局使用百分比、Grid布局等实现不同屏幕尺寸适配。typescriptComponent struct ResponsiveLayout { State currentBreakpoint: string sm; aboutToAppear() { this.updateBreakpoint(); window.on(sizeChange, () this.updateBreakpoint()); } updateBreakpoint() { let width window.getWindowWidth(); if (width 520) this.currentBreakpoint sm; else if (width 840) this.currentBreakpoint md; else this.currentBreakpoint lg; } build() { Grid() { if (this.currentBreakpoint lg) { // 大屏三列布局 GridItem() { /* 内容 */ } GridItem() { /* 内容 */ } GridItem() { /* 内容 */ } } else if (this.currentBreakpoint md) { // 中屏两列布局 GridItem() { /* 内容 */ } GridItem() { /* 内容 */ } } else { // 小屏单列布局 GridItem() { /* 内容 */ } } } } }6.2 原子化服务卡片开发服务卡片实现快速信息展示。typescript// form/NoteWidget.ets Entry Component struct NoteWidget { Prop latestNote: string; build() { Column() { Text(最新笔记) .fontSize(12) .fontColor(#666666) Text(this.latestNote) .fontSize(16) .fontWeight(FontWeight.Bold) .maxLines(2) .textOverflow({ overflow: TextOverflow.Ellipsis }) .margin({ top: 4 }) Button(快速记录) .width(100%) .height(30) .fontSize(12) .margin({ top: 8 }) } .padding(12) .width(100%) .height(100%) .backgroundColor(#FFFFFF) } }