鸿蒙应用入门级开发者认证实验四(华为商城应用页面)

HarmonyOS项目打开时自动执行ohpm install和build init是IDE(如DevEco Studio)的默认行为。通过oh-package.json5管理三方库依赖(如@hw-agconnect/cloud等),这些依赖存储在oh_modules目录。IDE检测到项目包含oh-package.json5文件时,会主动执行ohpm install以确保所有依赖完整安装。build init用于初始化hvigor构建环境,生成必要的构建缓存和配置文件。验证项目结构合规性(如工程路径不能包含隐藏目录)、加载构建插件、配置内存参数(如NODE_OPTS="--max-old-space-size=10240")。
class NavigationViewModel {
getLinkData(): Array<NavigationModel> {
// 代码逻辑...
}
}
let navigationViewModel = new NavigationViewModel()
export default navigationViewModel as NavigationViewModel
实现了一个商品分类数据处理器,将扁平的商品数据LINK_DATA按父分类ID(superId)分组,生成层级化的商品分类结构
- 输入:原始商品数据
LINK_DATA - 输出:
NavigationModel[]数组,每个元素包含:superId:父分类IDsuperName:父分类名称GoodsList:属于该分类的子商品列表
getLinkData(): Array<NavigationModel> {
let linkDataList: Array<NavigationModel> = [] // 结果数组
let superId: number = 0 // 跟踪当前父分类ID
LINK_DATA.forEach((item: LinkDataModel) => {
// 发现新父分类时创建分类节点
if (superId !== item.superId) {
let GoodsItem = new NavigationModel(item.superId, item.superName, [])
linkDataList.push(GoodsItem)
}
// 创建商品项并添加到当前分类
let GoodsItem = new GoodsModel(
superId,
item.id,
item.GoodsName,
item.imageUrl,
item.price
)
linkDataList[linkDataList.length - 1].GoodsList.push(GoodsItem)
superId = item.superId // 更新当前父分类ID
})
return linkDataList
}
- 分类识别:通过比较相邻项的
superId检测父分类变化 - 分类节点创建:当
superId变化时,创建新的NavigationModel实例 - 商品挂载:将每个商品挂载到最近创建的父分类节点下
- 数据转换:将一维数组转化为树形结构
NavigationViewModel两次出现,第一次出现:类定义
class NavigationViewModel { ... }
第二次出现:
let navigationViewModel = new NavigationViewModel()
export default navigationViewModel as NavigationViewModel
创建单例并导出,单例模式确保全局唯一实例,避免重复创建。通过export default暴露服务接口,as NavigationViewModel确保TS类型推断
但是上面的创建GoodsModel的循环代码可能存在问题:superId初始值为0(let superId:number=0)。(其实初始值-1比0更能避免真实ID冲突)当第一次执行循环时,item.superId必定不等于0(商品分类ID通常从1开始),此时会创建新的NavigationModel(使用item.superId),但创建GoodsModel时使用的仍是初始值0(而非当前商品的item.superId),这样造成数据不一致风险:商品对象的superId属性(0)与它实际所属的分类ID(item.superId)不匹配,可能导致后续数据关联错误(如父子分类关系断裂)。所以这是我觉得这个实验存在的一个问题。
?符号是可选属性标记,
item?: GoodsModel; // 关键声明
表示item属性是可选的,允许该属性值为GoodsModel类型或undefined,无需在构造函数或初始化时强制赋值,访问该属性时需做空值检查
// 未声明?时(必需属性)
item: GoodsModel; // 必须显式初始化,否则编译报错
// 声明?后(可选属性)
item?: GoodsModel; // 允许延迟初始化(如生命周期函数中赋值)
生命周期配合 在aboutToAppear()中的实际使用:
aboutToAppear(): void {
this.item = JSON.parse(this.itemStr); // 安全赋值点
}
利用组件生命周期确保使用前完成初始化、避免在build()等渲染阶段访问未定义值
组件通过层级嵌套形成类似树(Tree)的数据结构,能清晰描述组件间的层级关系(如父子、祖先后代),并高效实现数据传递(从根节点向下流动或跨层级同步)。
- 根节点:入口组件(
@Entry装饰的组件)作为树的根。 - 父节点:包含子组件的组件,如
ParentComponent。 - 子节点:被父组件引用的组件,如
ChildComponent。 - 叶子节点:不包含子组件的底层组件(如按钮、文本)。
用于父子组件数据同步的装饰器及其特性:
| 装饰器组合 | 同步方向 | 适用场景 | 关键特性 |
|---|---|---|---|
@State → @Prop |
单向 | 父→子单向数据流 | 子组件接收父组件数据,但子组件修改不同步回父组件。 |
@State → @Link |
双向 | 父子双向同步 | 父子组件共享数据源,任意一方修改都会触发同步。 |
@ObjectLink + @Observed |
双向 | 嵌套对象/复杂类型同步 | @Observed装饰类,@ObjectLink监听对象属性变化,支持深层次数据同步。 |
@Provide → @Consume |
双向 | 跨层级传递(祖先→后代) | 避免逐层传递,后代组件直接消费祖先提供的数据。 |
- 单向 vs 双向:
@Prop仅支持父→子单向同步;@Link、@ObjectLink、@Provide/@Consume支持双向同步。 - 数据复杂度:
- 简单类型(string/number/boolean)适用
@Prop、@Link。 - 对象/数组类型优先用
@ObjectLink或@Provide/@Consume。
- 简单类型(string/number/boolean)适用
- 层级限制:
@Provide/@Consume突破父子层级,适合跨多级组件传递数据。
设计建议:
- 简单父子通信用
@State+@Link;- 跨代组件用
@Provide+@Consume- 嵌套对象同步务必搭配
@Observed
- 点赞
- 收藏
- 关注作者
评论(0)