鸿蒙开发绕不开的四个核心问题,我整理了一份答案...
黄sir我做培训这些年,我发现学员问的问题,翻来覆去就那么几类。刚入门的时候问语法,学了一段时间问架构,真正做项目了问性能优化。今天把这四类高频问题系统梳理一遍,都是实战中踩出来的经验,没有废话。先说清楚原理:ArkUI的响应式系统,监听的是引用,不是属性。// 错误,这样做,页面纹丝不动@State user: User = { name: '张三', age: 25 }this.user.name = '李四'// 正确,改了引用,UI才会刷新this.user = { ...this.user, name: '李四' }
搞清楚这个原理之后,@State、@Prop、@Link的区别就很好理解了:@Entry@Componentstruct Parent { @State parentCount: number = 0 @State userName: string = '学员' build() { Column() { Text(`父组件: ${this.parentCount}`) // @Prop:单向传值,子组件收到后是独立拷贝,改不了父组件 StatusDisplay({ label: '学习进度', value: this.userName }) // @Link:双向绑定,传的是引用,子组件改了父组件同步变 Counter({ count: $parentCount }) } }}@Componentstruct Counter { @Link count: number // 双向绑定 build() { Row() { Button('计数-').onClick(() => this.count--) Text(`${this.count}`).fontSize(24).fontWeight(FontWeight.Bold).margin({ left: 12, right: 12 }) Button('计数+').onClick(() => this.count++) } }}
记住一个原则:只读的数据用@Prop,需要双向联动的用@Link。列表卡顿这个问题,几乎每个项目组都会问到。很多人第一反应是手机性能不够?不是,是渲染方式有问题。// 用ForEach渲染大数据量,必卡ForEach(this.products, (item: Product) => { ListItem() { ProductCard({ product: item }) }}, (item: Product) => item.id)
ForEach一次性把所有数据都渲染出来,上千条的时候内存和渲染开销都会爆炸。换用LazyForEach,按需加载:class ProductDataSource implements BasicDataSource { private products: Product[] = [] totalCount(): number { return this.products.length } getData(index: number): Product { return this.products[index] } pushData(product: Product) { this.products.push(product) this.notifyDataAdd(this.products.length - 1) }}List() { LazyForEach(this.dataSource, (product: Product) => { ListItem() { Row() { Text(product.name).fontSize(16) Blank() Text(`¥${product.price.toFixed(2)}`).fontColor('#FF6600') } .padding(16) } }, (product: Product) => product.id)}
LazyForEach:只搬货架能放下的那部分,看下一页再搬问题三:如何设计一个合理的项目结构
项目大了必须分层。我推荐这个结构:
entry/src/main/ets/├── entryability/│ └── EntryAbility.ets // 应用入口├── pages/│ └── Index.ets // 首页├── view/│ ├── components/ // 可复用组件│ │ ├── HeaderBar.ets│ │ └── ProductCard.ets│ └── pages/ // 页面组件│ ├── Detail.ets│ └── Settings.ets├── viewmodel/ // 视图模型层│ ├── HomeViewModel.ets│ └── DetailViewModel.ets├── model/ // 数据模型层│ ├── User.ets│ └── Product.ets├── service/ // 服务层│ ├── HttpService.ets│ └── StorageService.ets└── utils/ ├── Logger.ets └── Constants.ets
这样做的好处是什么?改东西的时候知道去哪找。页面换UI去view,逻辑要改去viewmodel,接口要换去service。问题四:网络请求怎么封装才合理
直接用http模块裸写,每个接口都重复配置header、超时、错误处理,代码会变得又臭又长。
封装一层请求服务:
// http/HttpService.etsimport http from '@ohos.net.http';class HttpService { private baseUrl: string = '' private defaultHeaders: Record<string, string> = { 'Content-Type': 'application/json' } setToken(token: string) { this.defaultHeaders['Authorization'] = `Bearer ${token}` } private async request<T>(url: string, method: http.RequestMethod, data?: object): Promise<T> { const request = http.createHttp() const fullUrl = this.baseUrl ? `${this.baseUrl}${url}` : url const response = await request.request(fullUrl, { method, header: this.defaultHeaders, extraData: data ? JSON.stringify(data) : undefined, connectTimeout: 30000, readTimeout: 30000 }) if (response.responseCode >= 200 && response.responseCode < 300) { return JSON.parse(response.result as string) as T } else { throw new Error(`请求失败: ${response.responseCode}`) } } get<T>(url: string): Promise<T> { return this.request<T>(url, http.RequestMethod.GET) } post<T>(url: string, data?: object): Promise<T> { return this.request<T>(url, http.RequestMethod.POST, data) } put<T>(url: string, data?: object): Promise<T> { return this.request<T>(url, http.RequestMethod.PUT, data) } delete<T>(url: string): Promise<T> { return this.request<T>(url, http.RequestMethod.DELETE) }}export const httpService = new HttpService()
class HomeViewModel { @State products: Product[] = [] @State loading: boolean = false @State error: string = '' async loadProducts() { this.loading = true try { this.products = await httpService.get<Product[]>('/products') } catch (e) { this.error = '加载失败' } finally { this.loading = false } }}
接口怎么调、超时怎么配、错误怎么处理,都不用在每个页面重复写。上面这四个问题,是鸿蒙开发里绕不开的核心内容。把这几个搞透了,后面的项目开发会顺畅很多。如果你现在还在自己摸索,文档东看一点西看一点,没有系统化的学习路径,我把我这些年整理的学习资料分享出来。
当时整理这份资料,是为了方便自己上课用。后来发现很多学员在外面找的资料要么太旧、要么太散,干脆整理成了一套完整的东西。想领取的话,私信回复「学习包」,我看到会发链接。有问题也可以直接问我,做了这么多年培训,帮你避几个坑还是做得到的。