鸿蒙应用入门级开发者认证实验五(短视频应用)

举报
黄生 发表于 2025/12/22 22:41:44 2025/12/22
【摘要】 在应用页面的开发中,为了提高开发效率以及方便后续代码维护。开发者首先可以将一个完整页面拆分成多个自定义组件构成。这一部分的拆解分析我们已经完成一大半了。然后,我们可以把这一部分UI所展示的数据进行数据模型提炼。提炼完模型之后,再对模型进行具体的数据导入。那么,再最后这一部分UI描述代码书写中,组件就可以直接调用我们先前构建好的数据模型进行使用。 对这个至关重要的开发顺序逻辑了解清晰之后,接下...

在应用页面的开发中,为了提高开发效率以及方便后续代码维护。开发者首先可以将一个完整页面拆分成多个自定义组件构成。这一部分的拆解分析我们已经完成一大半了。然后,我们可以把这一部分UI所展示的数据进行数据模型提炼。提炼完模型之后,再对模型进行具体的数据导入。那么,再最后这一部分UI描述代码书写中,组件就可以直接调用我们先前构建好的数据模型进行使用。 对这个至关重要的开发顺序逻辑了解清晰之后,接下来,我们就一起来构建具体的数据模型。

模型提炼的本质 :UI展示的每个数据点都是模型属性(以电商商品页为例)

// 从UI反推模型结构
class ProductModel {
  id: number;          // 商品ID(对应UI中的隐藏标识)
  name: string;        // 商品名称(标题文本)
  price: number;       // 价格(需格式化显示)
  stock: number;       // 库存(控制“售罄”标签显示)
  images: string[];    // 轮播图数组
}

不是先设计模型再写UI,而是根据UI展示需求定义模型属性

数据导入的工程化实践

  • 静态初始化(适用于原型开发):

    const mockData: ProductModel[] = [
      {id:1, name:"无线耳机", price:299, stock:10, images:["img1.png","img2.png"]}
    ]
    
  • 动态注入(真实场景):

    // 网络请求返回数据转换
    fetchProducts().then(rawData => {
      productList = rawData.map(item => new ProductModel(item))
    })
    

    永远在模型层做数据清洗(如价格单位转换/空库存处理)

组件与模型的共生关系

@Component
struct ProductCard {
  // 核心绑定:组件直接消费模型实例
  @Link product: ProductModel  

  build() {
    Column() {
      Text(this.product.name)  // 直接读取模型属性
      PriceDisplay({value: this.product.price}) // 子组件二次封装
      StockTag(this.product.stock) // 根据库存值动态生成UI
    }
  }
}

当后端API字段变更时,只需修改ProductModel映射逻辑

拆解UI组件
定义数据模型
实现数据管道
组件绑定模型
需求变更只需改模型

模型分层

  • 基础模型:纯数据结构(如ProductModel
  • 服务模型:包含业务逻辑的方法(如ProductService.checkStock()
  • 视图模型:为特定页面优化的数据结构(如ProductVM.getDisplayPrice()

这种模型优先的开发范式,本质是把数据流控制权从UI层抽离。

Swiper 轮播组件实现自动播放功能(swiper是一个滑动或刷动某物的人或工具),通过 setInterval 定时器,每隔 CommonConstants.SWIPER_TIME 毫秒调用 swiperController.showNext() 方法,实现轮播内容的自动切换。将生成的定时器 ID 存入全局数组 timerIds,便于后续统一管理(如停止播放时清除所有定时器)。

// 设置定时器:每隔 SWIPER_TIME 时间切换到下一项
let timerId = setInterval(() => {
  swiperController.showNext();  // 调用 SwiperController 的切换方法
}, CommonConstants.SWIPER_TIME);

// 保存定时器 ID(用于后续停止播放)
timerIds.push(timerId);

需配套实现 stopPlay() 方法,遍历 timerIds 调用 clearInterval 清除定时器,避免内存泄漏。

    Navigator({ target: CommonConstants.HOME_PAGE, type: NavigationType.Back }) {
      Row({ space: CommonConstants.SPACE_NAVIGATION }) {
        Image($r('app.media.ic_back'))
          .width(CommonConstants.WIDTH_BACK_ICON)
          .height(CommonConstants.HEIGHT_BACK_ICON)
          .objectFit(ImageFit.Contain)

        Text($r('app.string.movie'))
          .fontSize(CommonConstants.FONT_SIZE_TITLE)
          .fontWeight(CommonConstants.FONT_WEIGHT_BOLD)
          .fontColor($r('app.color.start_window_background'))
          .textAlign(TextAlign.Center)
          .margin(CommonConstants.MARGIN_PLAY_PAGE)
          .lineHeight(CommonConstants.LINE_HEIGHT_NAVIGATION)
      }
    }
    // TODO
    .position({ x: CommonConstants.LEFT_POSITION, y: CommonConstants.START_POSITION })

Navigator 是早期的页面导航组件,无法灵活管理页面栈(如跨页面传参、动态路由解析),缺少统一的导航状态管理机制,与新的声明式开发范式(ArkUI)兼容性不足。HarmonyOS 为提升开发效率和性能,推出更强大的 Router 模块作为替代方案。移除旧组件可避免冗余 API 对开发者的干扰。通过 @kit.ArkUIrouter 实现导航功能: 返回目标页面(对应原 NavigationType.Back

import router from '@kit.ArkUI';

// 返回指定路径的页面(如主页)
router.back({ 
  url: CommonConstants.HOME_PAGE  // 目标页面路径
});

但似乎Router只是替代 Navigator 的过渡方案。

@Link @Watch('needPageShow') index: number;
@Link @Watch('needPageShow') pageShow: boolean;

@Watch 的作用 :当被装饰的状态变量(如 indexpageShow)的值发生变化时,自动触发指定的回调函数(这里是 needPageShow)。这是一种响应式编程模式。回调函数要求:必须是无参函数(参数由系统自动注入),第一个参数:变化后的新值,第二个参数:变化前的旧值。@Watch 回调中不应直接修改当前监听的状态变量,否则可能导致循环更新。如需要修改状态,请使用异步机制或操作其他状态变量。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。