Trigger Scenarios
This Skill should be enabled as the specification basis for ArkTS code generation and review when any of the following conditions is met:
- The user is editing or creating a
.etsfile and mentions keywords such as "specification", "best practices", "code style", "code review", etc. - There appear in the conversation ArkTS / ArkUI / HarmonyOS NEXT related issues, especially component writing, lifecycle, styles and layout, event handling, state management, error handling, and testing practices.
- The user requests "write ArkTS code according to official/industry best practices" or "help me check/refactor ArkTS pages/components/modules according to the specification".
In these scenarios, the ArkTS code generated or modified by the agent must refer to the specification content in this Skill.
Main Goals of the Skill
- Unify state management versions: Unify state management in the project, prioritizing the V2 version to implement ViewModel. Commonly used state management decorators include @Local, @Param, @Event, @ObservedV2, @Trace, and so on.
- Unify component decorators and state management usage: Ensure entry components, page components, and custom components use the correct decorators,
@State/@Prop/@Link/@Provide/@Consumeetc. are selected according to data flow semantics. - Standardize lifecycle usage: Correctly initialize and clean up resources in
aboutToAppear/aboutToDisappear/onPageShow/onPageHideto avoid memory leaks. - Unify styles and layout style: Use chained calls, reasonable property order, and responsive units (
vp/fp/ percentage) to build UI and keep the ArkUI style consistent. - Constrain event handling methods: Use arrow functions and private methods to encapsulate complex logic, avoiding directly stacking complex business code in
build(). - Strengthen type safety: Clarify data structures and callback signatures between components through interfaces and generics, avoiding implicit
anyunknownand weakly typed code. - Focus on performance and resource management: Avoid unnecessary rendering, use
@Reusable、@Builder、LazyForEachreasonably, and correctly release resources in the lifecycle. - Standardize error handling and logging: Add
try/catchandPromise.catchfor asynchronous flows, and usehilogfor standardized log output. - Emphasize testing and code self-check: Guide the writing of
@ohos/hypiumunit tests for components, and use the accompanying code review checklist for pre-submission self-check.
Skill Usage Requirements and Output Style
When using this Skill to answer ArkTS-related questions or generate code, the agent should:
-
Automatically correct code against the specification
- If a component is found to be missing or misusing a decorator (such as
@Entry、@Component、@Stateetc.), it should be automatically completed or corrected according to the specification. - If there is a risk of resource leakage in the lifecycle (such as an uncleaned timer), cleanup logic should be added in
aboutToDisappear(). - If the chained style call order is disordered or attributes from different categories are mixed, rearrange them in the order of "size → layout → background → border → text → alignment → interaction".
- If a component is found to be missing or misusing a decorator (such as
-
Prioritize outputting example code that conforms to the specifications
- When explaining scenarios such as component design, state management, list rendering, and event handling, the example code must follow the conventions stipulated by this Skill.
- For "non-compliant examples" provided by the user, first point out the points that do not conform to this specification, then provide the "✅ Recommended approach".
-
Explicitly reference the relevant section guidance
- In the response, you may mention "refer to this Skill's Component Decorator Specification / Lifecycle Specification / Style and Layout Specification / Event Handling Specification / Type Safety Specification / Performance Optimization Specification / Error Handling Specification / Testing Specification section".
- In code review responses, suggestions may be given item by item according to the "Code Review Checklist" at the end of the document.
-
Keep explanations moderate and practice-oriented
- When responding, focus on "how to write correct ArkTS code", appropriately cite specification key points, but avoid lengthy theoretical stacking.
- For key specifications (such as lifecycle cleanup, state decorator selection, error handling, etc.), provide brief explanations of the reasons to help users understand rather than memorize by rote.
⚠️ Mandatory Requirements (Must Be Strictly Followed)
When using this Skill for development,you must strictly followthe following specifications:
-
Build and Compilation Verification Specification (Auto Run):
- ✅ When involving ArkTS syntax structure adjustments(including but not limited to component decorators, lifecycle function signatures, state management decorators, interface/type declarations, etc.) or dependency-related changes(such as
oh-package.json5、module.json5, introduction or removal of third-party SDKs), after completing the main modifications, an automated "auto run" build process should be triggered once, rather than manually compiling only at a few nodes. - ✅ It is recommended to configure scripts, IDE Tasks, or CI pipelines in the project root directory so that the following is automatically executed before each commit:
ohpm installhvigorw assembleHap --mode module -p product=default -p buildMode=debug --no-daemonEnsure that both ArkTSCheck and the packaging process can pass.
- ✅ After multiple consecutive rounds of ArkTS refactoring or large-scale renaming, the above auto run process should be manually or automatically repeated at appropriate milestone nodes to expose type / syntax / dependency issues as early as possible.
- ❌ It is prohibitedto rely only on local Lint or static analysis results and skip hvigor real device / emulator compilation verification or the agreed auto run process when there are ArkTS syntax or dependency changes.
- ✅ When involving ArkTS syntax structure adjustments(including but not limited to component decorators, lifecycle function signatures, state management decorators, interface/type declarations, etc.) or dependency-related changes(such as
-
Log Output Specification:
- ✅ mustuse
Loggerutility class to encapsulate nativeconsole - ✅ The first parametermustfixedly use the scene name
"SportHealthMap" - ✅ The second parameter uniformly uses
string | object, and it is recommendedto directly pass in an object, withLoggerresponsible for JSON serialization - ✅
LoggerThe utility class will automatically performJSON.stringifyserialization on non-string parameters - ❌ It is prohibitedUse directly
console.info/error/warn/debug - Example (recommended usage):
Logger.info('SportHealthMap', JSON.stringify({ action: 'mapReady' }))
- ✅ mustuse
-
Code Comment Standards:
- ✅ MustAdd comments to key methods, explaining purpose, parameters, and return values
- ❌ ProhibitedMeaningless comments
-
Modularization Standards:
- ✅ MustDefine general utility classes, components, similar Interface and other types in separate files
- ❌ ProhibitedDefine general classes inline within page components
-
Performance Optimization Standards:
5.1 Object Caching and Reuse
- ✅ MustIn high-frequency UI update scenarios, objects must be cached and reused, holding references through member variables rather than rebuilding each time
- ✅ MustHeavyweight objects (custom drawing components, animation controllers, data adapters, etc.) must be managed using the Object Pool pattern, pre-allocated and acquired/returned on demand
- ❌ ProhibitedRepeatedly creating and removing objects for the same function (e.g., repeatedly new then remove in timed callbacks / data refreshes)
- ❌ ProhibitedIn
build()method or@Builderfunction, new any non-lightweight value object
5.2 Rendering Performance
- ✅ MustIn list scenarios with more than 20 items, use
LazyForEach+IDataSourceto implement on-demand loading; rendering all data at once is prohibited - ✅ MustUse
@Builderto extract repeated UI description fragments, avoidingbuild()large amounts of repeated code - ✅ RecommendedFor conditional rendering, prefer using
if/elseto control component tree branches, rather than using.visibility(Visibility.None)to hide (the latter still participates in layout calculation) - ❌ ProhibitedIn
build(), perform time-consuming calculations, network requests, or file I/O
5.3 Refined State Management
- ✅ MustSplit high-frequency changing state and low-frequency state into different
@State/@Observedproperties, avoiding unrelated property changes triggering re-rendering of the entire component tree - ✅ RecommendedUse
@Watchdecorator to listen for specific state changes and execute side effects, replacingbuild()difference checking - ✅ RecommendedFor cross-level data transfer, prefer using
@Provide/@Consumeor AppStorage, rather than layer-by-layer@Proppassing - ❌ ProhibitedAssign a large array or deeply nested object as a whole to
@State; instead use@Observed+@ObjectLinkto achieve property-level precise refresh
5.4 Asynchrony and Concurrency
- ✅ MustPlace time-consuming operations (network requests, database queries, file read/write, large-scale computations) into
TaskPoolorWorkerthread execution; blocking the UI thread is prohibited - ✅ Must
TaskPool.execute()Add.catch()fallback to the returned Promise to avoid silently discarding exceptions - ✅ RecommendedFor batch concurrent requests, use
Promise.all()/Promise.allSettled()to merge, reducing thread scheduling overhead - ❌ ProhibitedIn the timer callback (
setInterval/setTimeout) directly executing heavy business logic should be moved to the background via message dispatch or TaskPool
5.5 Memory Management
- ✅ MustIn
aboutToDisappear()clean up all timers (clearInterval/clearTimeout), event subscriptions (emitter.off), sensor listeners, callback registrations, etc. - ✅ MustAfter large images / Bitmap resources are used, explicitly call
release()or set the reference to null, and cooperate with GC for timely reclamation - ✅ RecommendedUse
WeakRefto hold object references that are only observed but do not prevent reclamation, avoiding closures unexpectedly extending the lifecycle - ❌ ProhibitedHolding strong references to other component instances within a component, causing cross-references that cannot be reclaimed
- ❌ ProhibitedAccumulating data indefinitely in global singletons (AppStorage / static variables) without setting an upper limit or eviction policy
5.6 Startup and Loading Optimization
- ✅ RecommendedNon-first-screen modules use dynamic
import()lazy loading to reduce the main package size and cold start time - ✅ RecommendedFirst-screen data prefetching in parallel with UI construction: while
aboutToAppear()initiates the request, display a skeleton screen / Loading placeholder - ❌ ProhibitedIn Ability
onCreate()execute blocking synchronous calls (such as synchronously reading large files, synchronous network requests)
5.7 Package Size and Build Artifacts
- ✅ RecommendedRegularly execute
hvigorw analyzeBundleto analyze package size, identify and remove unused resources and dependencies - ✅ RecommendedThird-party SDKs should import submodules on demand, avoiding full imports (such as
import { SpecificApi } from '@third/sdk'instead ofimport * as sdk from '@third/sdk') - ❌ ProhibitedRetaining
console/hilog.debuglevel log output in release builds; it should be masked through build configuration or log level switches
-
Type Declaration:
- ✅ MustCustom Object objects must first define the type through an Interface, then reference the type definition for data, and then use
- ❌ ProhibitedUse
anyunknowntype annotation - Example (recommended usage):
export interface Out{ xx: string} function getBaseLocation():Out{let m = {xx:'XXX'};return m}
When generating or reviewing ArkTS code, the agent should preferentially refer to the following content.
0. ArkTS Type and Null Safety Specifications
This section, based on the original "Type Safety Specifications", supplements the mandatory rules related to ArkTSCheck and null safety conventions, used to unify the type design, null handling, and syntax constraints of ArkTS code.
1. Mandatory Type Safety Rules
- Parameters and return values must be explicitly typed: Implicit
anyunknownis prohibited. The parameters and return values of all functions, methods, and callbacks must have their types written out. - Interface-driven data structure design: For component
@State/@Prop/@Link, service input/output parameters, global configuration, etc., preferentially define the structure throughinterface/ type aliases, and then reference them in the code. - Accessing undeclared fields is prohibited: Accessing properties not declared in the type via string indexing is not allowed; when a "dictionary" structure is truly needed, use an index signature:
interface StringNumberMap {
[key: string]: number;
}
2. Null safety strategy
- Explicitly handle
null/undefined: For types ofT | null | undefinedor optional properties with?:, before access you must use optional chaining or explicit null checks. - Recommended写法:
- Optional chaining:
user?.name、config?.options?.timeout ?? 3000; - Explicit null check:
if (user !== null && user !== undefined) { ... }。
- Optional chaining:
- Avoid overusing the non-null assertion
!: Only when the null branch has already beenfully coveredthrough logical branches, early returns, throwing errors, etc., is it allowed to use!, and it is recommended to add a comment explaining the reason.
3. Function declarations and structural constraints (ArkTSCheck syntax rules)
- Destructured variable declarations are prohibited:
ArkTSdoes not supportconst { a, b } = objdestructured variable declarations in the form (arkts-no-destruct-decls), and they must be rewritten as one-by-one assignments:
// ❌ 不允许
const { lat, lng } = coord;
// ✅ 推荐
const lat = coord.lat;
const lng = coord.lng;
- Avoid parameter destructuring in business functions: It is recommended to define an interface or independent parameters for the parameters, rather than
function draw({ text, location }) { ... }such forms that make types hard to trace. - Prefer arrow functions inside components: When defining event callbacks or small internal functions in
build(),const handler = (): void => { ... }is recommended, which helps with type inference and clear closure semantics.
4. Supplementary ArkUI component property constraints
TextInputdoes not support theplaceholderproperty:TextInputAttributehas noplaceholder, and you cannot call.placeholder()or set a placeholder via constructor parameters.- Recommended alternatives for placeholder needs:
- Use the label text above to indicate the input meaning;
- Use
Stackto conditionally render a grayTextoverlaid onTextInput, displayed when the input content is empty; - If the current HarmonyOS version supports it, you can use
.placeholderFont()/.placeholderColor()and other APIs, rather than a custom.placeholder()。
5. Type system constraints and interface design
- Avoid relying on purely structural equivalent assignment: Do not assign between two classes to each other just because their fields "look the same"; they should be uniformly constrained through an interface or base class:
interface WithNumber {
n: number;
}
class X implements WithNumber {
n: number = 0;
}
class Y implements WithNumber {
n: number = 0;
}
let value: WithNumber = new X(); // ✅ 通过公共接口约束
- When modeling and refactoring, prioritize:
- Define domain interfaces / abstract base classes;
- Have concrete implementations
implements/extendsthese common types, rather than assigning directly between different classes.
6. Comprehensive example: type-safe + null-safe route navigation
In scenarios involving route tables, an interface must be defined for the route configuration, and null handling must be done for the find result and the optional path :
interface RouteConfig {
id: string;
path?: string;
}
const routes: RouteConfig[] = [
{ id: 'home', path: 'pages/Home' },
{ id: 'detail', path: 'pages/Detail' }
];
function navigateToPage(pageId: string): void {
const targetRoute: RouteConfig | undefined = routes.find(
(route: RouteConfig) => route.id === pageId
);
if (targetRoute?.path) {
router.push({ url: targetRoute.path });
return;
}
if (!targetRoute || !targetRoute.path) {
// 记录日志或给出兜底处理
return;
}
router.push({ url: targetRoute.path });
}
When answering similar questions, the above patterns should be used to simultaneously ensure:
- All parameters / return values have explicit types;
- The configuration structure is constrained through interfaces;
- Fields and lookup results that may be null are fully validated.
1. Component decorator specifications
1.1 Components must use decorators
- Entry componentmust use the
@Entrydecorator - Page componentmust use the
@Componentdecorator - Custom componentmust use the
@Componentdecorator
// ✅ 正确示例
@Entry
@Component
struct Index {
// 组件实现
}
@Component
struct ChildChip {
// 组件实现
}
1.2 State Management Decorators
Choose the appropriate decorator based on the direction of data flow:
@State: State internal to the component; changes trigger UI updates@Prop: Read-only data passed from the parent component to the child component@Link: Data with two-way binding between parent and child components@Provide/@Consume: Data sharing across component levels@Observed/@ObjectLink: Reactive updates at the object property level@StorageProp/@StorageLink: Persistent storage
@Component
struct ParentComponent {
@State count: number = 0; // 内部状态
@State message: string = "Hello";
build() {
Column() {
ChildComponent({ count: this.count, message: this.message })
}
}
}
@Component
struct ChildComponent {
@Prop count: number; // 只读属性
@Link message: string; // 双向绑定
build() {
// ...
}
}
2. Component Lifecycle Specifications
2.1 Lifecycle Decorators
Lifecycle methods must be defined in the specified order:
aboutToAppear(): Called when the component is about to be displayedaboutToDisappear(): Called when the component is about to disappearonPageShow(): Called when the page is displayed (Page components only)onPageHide(): Called when the page is hidden (Page components only)
@Component
struct MyComponent {
private timerId: number | undefined = undefined;
aboutToAppear() {
// 初始化数据
this.timerId = setInterval(() => {
// 定时任务
}, 1000);
}
aboutToDisappear() {
// 清理资源
if (this.timerId) {
clearInterval(this.timerId);
}
}
}
3. Style and Layout Specifications
3.1 Chained Calls
Style properties must use chained calls, organized in the following order:
- Size properties:
.width(),.height(),.size() - Layout properties:
.margin(),.padding() - Background properties:
.backgroundColor(),.backgroundImage() - Border properties:
.borderRadius(),.borderWidth(),.borderColor() - Text properties:
.fontSize(),.fontColor(),.fontWeight() - Alignment properties:
.justifyContent(),.alignItems() - Interaction properties:
.onClick(),.onTouch()
// ✅ 最佳实践
Text('Hello ArkTS')
.fontSize(20)
.fontColor(Color.White)
.fontWeight(FontWeight.Bold)
.backgroundColor('#4F8DFF')
.padding({ left: 16, right: 16, top: 8, bottom: 8 })
.borderRadius(8)
.onClick(() => {
// 点击事件
})
// ❌ 避免:混合编码风格
Text('Hello ArkTS')
.fontSize(20).backgroundColor('#4F8DFF') // 不应该混合不同类型的属性
3.2 Responsive Units
- Prefer percentages:
'100%'instead of fixed values - Recommended to use
vp(virtual pixels) to adapt to different resolutions - Text uses
fp(font pixels) to ensure font size consistency
// ✅ 响应式设计
Column()
.width('100%')
.height('100%')
.padding(10)
Text('标题')
.fontSize(16)
.margin({ top: 10 })
4. Event Handling Specifications
4.1 Event Callback Functions
- Use arrow functions to avoid this binding issues
- Encapsulate complex logic in private methods
- Avoid writing complex logic directly in the build method
@Component
struct MyComponent {
@State count: number = 0;
private handleClick() {
this.count++;
// 复杂逻辑处理
}
build() {
Column() {
Button('点击')
.onClick(() => {
this.handleClick(); // ✅ 调用封装的方法
})
// ❌ 避免:直接在事件中写复杂逻辑
Button('不推荐')
.onClick(() => {
this.count++;
fetchData().then(() => {
// 复杂异步逻辑
});
})
}
}
}
5. Type Safety Specifications
5.1 Interface Definitions
Data transfer between components must define explicit interfaces:
// ✅ 明确的接口定义
interface ChildInfo {
id: string;
name: string;
avatarColor: string;
}
@Component
struct ChildChip {
@Prop child: ChildInfo; // 明确指定类型
@Prop selected: boolean;
@Prop onSelect: (id: string) => void; // 明确的函数签名
build() {
// ...
}
}
5.2 Generic Usage
For reusable components, use generics to improve type safety:
@Component
struct ListItem<T> {
@Prop item: T;
@Prop renderItem: (item: T) => void;
build() {
// 渲染逻辑
}
}
6. Performance Optimization Specifications
6.1 Object Caching and Reuse
- In high-frequency update scenarios (such as real-time data refresh and animation frame updates), object references must be cached, updating only properties rather than destroying and recreating
- Use the object pool pattern to manage the allocation and recycling of heavy objects
// ✅ 通用对象池模式示例
class ObjectPool<T> {
private pool: Array<T> = [];
private activeMap: Map<string, T> = new Map();
private factory: (options: object) => T;
private resetter: (item: T, options: object) => void;
constructor(factory: (options: object) => T, resetter: (item: T, options: object) => void) {
this.factory = factory;
this.resetter = resetter;
}
/** 从池中取出或新建对象 */
acquire(id: string, options: object): T {
let item: T | undefined = this.pool.pop();
if (item === undefined) {
item = this.factory(options);
} else {
this.resetter(item, options);
}
this.activeMap.set(id, item);
return item;
}
/** 归还对象到池中 */
release(id: string): void {
const item: T | undefined = this.activeMap.get(id);
if (item !== undefined) {
this.activeMap.delete(id);
this.pool.push(item);
}
}
/** 释放全部资源 */
clear(): void {
this.activeMap.clear();
this.pool = [];
}
}
6.2 Rendering Performance Optimization
- Avoid creating new objects or arrays in the
build()method - Use the
@Reusabledecorator to mark reusable UI components - Large lists must use
LazyForEach+IDataSourceto implement on-demand loading
// ✅ LazyForEach + IDataSource 示例
class ListDataSource implements IDataSource {
private dataArray: Array<string> = [];
private listeners: Array<DataChangeListener> = [];
totalCount(): number {
return this.dataArray.length;
}
getData(index: number): string {
return this.dataArray[index];
}
registerDataChangeListener(listener: DataChangeListener): void {
this.listeners.push(listener);
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const idx: number = this.listeners.indexOf(listener);
if (idx >= 0) {
this.listeners.splice(idx, 1);
}
}
pushData(data: string): void {
this.dataArray.push(data);
this.listeners.forEach((listener: DataChangeListener) => {
listener.onDataAdd(this.dataArray.length - 1);
});
}
}
@Component
struct HighPerfList {
private dataSource: ListDataSource = new ListDataSource();
build() {
List() {
LazyForEach(this.dataSource, (item: string, index: number) => {
ListItem() {
this.ItemBuilder(item)
}
}, (item: string) => item) // keyGenerator 保证 diff 精准
}
.cachedCount(5) // 预加载屏外 5 项,平衡内存与流畅度
}
@Builder
ItemBuilder(item: string) {
Text(item)
.fontSize(14)
.margin({ bottom: 4 })
}
}
6.3 State Splitting and Precise Refresh
- Split high-frequency changing state and low-frequency state into different properties to avoid unrelated rendering
- For deeply nested objects, use
@Observed+@ObjectLinkto implement property-level refresh
// ✅ 状态拆分示例:高低频状态分离
@Observed
class RealtimeData {
value: number = 0;
updateTime: number = 0;
}
@Component
struct DashboardPage {
@State realtimeData: RealtimeData = new RealtimeData(); // 高频:实时数据刷新
@State configLoaded: boolean = false; // 低频:配置加载
build() {
Column() {
ConfigPanel() // 不受 realtimeData 变化影响
RealtimePanel({ data: this.realtimeData }) // 仅 realtimeData 变化时刷新
}
}
}
@Component
struct RealtimePanel {
@ObjectLink data: RealtimeData; // 精准订阅,不受父组件其他状态影响
build() {
Text(`${this.data.value} @ ${this.data.updateTime}`)
.fontSize(12)
}
}
6.4 Asynchronous Tasks and Thread Management
- Time-consuming operations must use
TaskPool/Workerfor execution; blocking the UI thread is prohibited
import { taskpool } from '@kit.ArkTS';
// ✅ 使用 TaskPool 执行耗时计算
@Concurrent
function parseJsonData(raw: string): Array<DataItem> {
// 在后台线程中解析大量 JSON 数据
const data: RawDataSet = JSON.parse(raw) as RawDataSet;
return data.items.map((item: RawItem) => {
return { id: item.id, value: item.value } as DataItem;
});
}
async function loadData(url: string): Promise<Array<DataItem>> {
const rawData: string = await fetchRawData(url);
const task: taskpool.Task = new taskpool.Task(parseJsonData, rawData);
const result: Array<DataItem> = await taskpool.execute(task) as Array<DataItem>;
return result;
}
6.5 Memory and Resource Lifecycle Management
- In
aboutToDisappear(), clean up all timers, event listeners, sensors, and callback registrations
@Component
struct ResourceManagedComponent {
private timerId: number | undefined = undefined;
private eventCallbackId: number | undefined = undefined;
private objectPool: ObjectPool<CustomItem> | undefined = undefined;
aboutToAppear(): void {
this.objectPool = new ObjectPool<CustomItem>(
(opts: object) => new CustomItem(opts),
(item: CustomItem, opts: object) => item.reset(opts)
);
this.timerId = setInterval(() => {
this.refreshData();
}, 5000);
this.eventCallbackId = emitter.on('dataUpdate', (data: EventData) => {
this.handleDataUpdate(data);
});
}
aboutToDisappear(): void {
// ✅ 逐一清理全部资源
if (this.timerId !== undefined) {
clearInterval(this.timerId);
this.timerId = undefined;
}
if (this.eventCallbackId !== undefined) {
emitter.off('dataUpdate');
this.eventCallbackId = undefined;
}
if (this.objectPool !== undefined) {
this.objectPool.clear();
}
}
private refreshData(): void { /* ... */ }
private handleDataUpdate(data: EventData): void { /* ... */ }
build() {
Column() {
Text('资源已管理')
}
}
}
6.6 Startup and Loading Optimization
- Non-first-screen modules use dynamic
import()for lazy loading - First-screen data prefetching runs in parallel with UI construction, showing a skeleton screen placeholder
// ✅ 动态导入 + 骨架屏示例
@Entry
@Component
struct MainPage {
@State dataReady: boolean = false;
@State listData: Array<ItemInfo> = [];
aboutToAppear(): void {
// 数据预取与 UI 构建并行
this.prefetchData();
}
private async prefetchData(): Promise<void> {
try {
this.listData = await fetchHomeList();
this.dataReady = true;
} catch (e) {
Logger.error('SportHealthMap', JSON.stringify({ action: 'prefetch_fail', error: e }));
}
}
build() {
Column() {
if (!this.dataReady) {
this.SkeletonBuilder() // 骨架屏占位
} else {
this.ContentBuilder()
}
}
}
@Builder
SkeletonBuilder() {
Column() {
ForEach([1, 2, 3, 4], () => {
Row()
.width('100%')
.height(60)
.backgroundColor('#F2F2F2')
.borderRadius(8)
.margin({ bottom: 12 })
})
}
.padding(16)
}
@Builder
ContentBuilder() {
List() {
LazyForEach(new HomeDataSource(this.listData), (item: ItemInfo) => {
ListItem() {
Text(item.title).fontSize(16)
}
}, (item: ItemInfo) => item.id)
}
}
}
6.7 Performance Measurement and Monitoring
- Critical path uses
hiTraceMetertracing points, verify frame rate and duration in SmartPerf
import { hiTraceMeter } from '@kit.PerformanceAnalysisKit';
// ✅ 性能打点示例
function renderListItems(items: Array<ItemInfo>): void {
hiTraceMeter.startTrace('renderListItems', 1);
// 批量渲染列表项
items.forEach((item: ItemInfo) => {
applyItem(item);
});
hiTraceMeter.finishTrace('renderListItems', 1);
}
7. Code Organization Standards
7.1 File Structure
entry/src/main/ets/
├── pages/ # 页面组件
│ ├── Index.ets
│ └── Detail.ets
├── components/ # 公共组件
│ ├── Button.ets
│ └── Card.ets
├── utils/ # 工具函数
│ ├── FormatUtils.ets
│ └── Validation.ets
├── models/ # 数据模型
│ ├── User.ets
│ └── Product.ets
└── services/ # 服务层
├── ApiService.ets
└── StorageService.ets
7.2 Import Standards
- Relative path imports:
import { ... } from '../utils/FormatUtils' - Absolute path imports:
import { ... } from '@kit.ArkUI' - Third-party library imports:
import { ... } from '@bdmap/map'
7.3 Naming Standards
- Component names: PascalCase, e.g.
UserProfile - Variable names: camelCase, e.g.
userName - Constant names: UPPER_SNAKE_CASE, e.g.
MAX_COUNT - Interface names: PascalCase, e.g.
UserInfo - Private members: camelCase, prefix may be added
_, e.g._internalData
8. Error Handling Standards
8.1 Asynchronous Error Handling
- Promises must have catch handling added
- Wrap code that may throw exceptions in try-catch
private async fetchData() {
try {
const response = await http.get('/api/data');
// 处理数据
} catch (error) {
promptAction.showToast({
message: '网络请求失败',
duration: 2000
});
// 记录日志
hilog.error(DOMAIN, 'App', 'Fetch data failed: %{public}s', JSON.stringify(error));
}
}
8.2 Logging Standards
import { hilog } from '@kit.PerformanceAnalysisKit';
const DOMAIN = 0x0000; // 定义日志域
// 不同级别的日志
hilog.debug(DOMAIN, 'Tag', 'Debug message'); // 调试信息
hilog.info(DOMAIN, 'Tag', 'Info message'); // 普通信息
hilog.warn(DOMAIN, 'Tag', 'Warning message'); // 警告信息
hilog.error(DOMAIN, 'Tag', 'Error message'); // 错误信息
9. Testing Standards
9.1 Unit Testing
- Each component should have corresponding unit tests
- Use
@ohos/hypiumtesting framework - Test files and source files maintain the same directory structure
9.2 Test File Naming
UserComponent.ets # 源码
UserComponent.test.ets # 对应测试文件
10. Code Review Checklist
Check each time [code generation is completed/code is submitted]:
- Whether the component uses the correct decorators
- Whether state management is correct (@State/@Prop/@Link)
- Whether lifecycle methods correctly clean up resources
- Whether styles use chained calls and the order is correct
- Whether event handling uses arrow functions
- Whether type definitions are complete
- Whether error handling is complete
- Whether logging is appropriate
- Whether performance considerations are sufficient (object cache reuse, LazyForEach, state splitting, asynchronous threading)
- Whether there is a risk of memory leaks (whether timers, event listeners, sensors, and callback registrations are cleaned up in aboutToDisappear)
- Whether the startup path has blocking synchronous calls
- Whether large lists use LazyForEach + IDataSource + cachedCount
- Whether high-frequency refresh scenarios use object pools / cache reuse
Applicable Version:HarmonyOS 4.0+
ArkTS Version:API 12+