【HarmonyOS】HarmonyOS NEXT学习日记:五、交互与状态管理

【HarmonyOS】HarmonyOS NEXT学习日记:五、交互与状态管理

在之前我们已经学习了页面布局相关的知识,绘制静态页面已经问题不大。那么今天来学习一下如何让页面动起来、并且结合所学完成一个代码实例。

交互

如果是为移动端开发应用,那么交互上用的最多的就是触屏事件。当然ArkUI也提供了键鼠事件、焦点事件、拖拽事件等。不过我认为用到的时候再看文档就行,事件这个东西一通百通,所以这里只介绍几个常用的事件。

onClick

点击事件是指通过手指或手写笔做出一次完整的按下和抬起动作。当发生点击事件时,会触发以下回调函数

用法:onClick(event: (event?: ClickEvent) => void)

event参数提供点击事件相对于窗口或组件的坐标位置,以及发生点击的事件源

我们写一个示例,点击按钮操作一个数字

ts 复制代码
  @State num: number = 0

  build() {
    Column({space: 10}){
      Text(`数字:${this.num}`)
      Button('数字+1').onClick(()=>{
        this.num++
      })
      Button('数字-1').onClick(()=>{
        this.num--
      })
    }
    .width('100%')
    .alignItems(HorizontalAlign.Center)
    }

点击数字+1按钮则数字变大1

触摸事件

当手指或手写笔在组件上触碰时,会触发不同动作所对应的事件响应,包括按下(Down)、滑动(Move)、抬起(Up)事件

用法:onTouch(event: (event?: TouchEvent) => void)

  • event.type为TouchType.Down:表示手指按下。
  • event.type为TouchType.Up:表示手指抬起。
  • event.type为TouchType.Move:表示手指按住移动。
ts 复制代码
@State eventType: string = ''

  build() {
    Column({space: 10}){
      Text(`eventType:${this.eventType}`)
      Button('触摸我').onTouch((event) => {
        if(event) {
          if (event.type === TouchType.Down) {
            this.eventType = 'Down';
          }
          if (event.type === TouchType.Up) {
            this.eventType = 'Up';
          }
          if (event.type === TouchType.Move) {
            this.eventType = 'Move';
          }
        }
      })
    }
    .width('100%')
    .alignItems(HorizontalAlign.Center)
    }

手在按钮上按下时

手在按钮上移动时

手松开按钮后

状态管理

但如果希望构建一个动态的、有交互的界面,就需要引入"状态"的概念。

事实上之前我们已经多次用到了这个概念,点击按钮改变一个字符串并让他展示在页面上,这个字符串就是一个状态。

即:点击交互触发了文本状态变更,状态变更引起了UI渲染

我们将写组件时用到的变量分为以下两种

  • 普通变量:只能在初始化时渲染,后续将不会再刷新。
  • 状态变量:需要装饰器装饰,改变会引起 UI 的渲染刷新 (必须设置类型 和初始值)

不论是哪种变量,只要是定义在组件内,在使用的时候,都需要通过 this 访问。

bash 复制代码
@Entry
@Component
struct Index {
  @State str1: string = 'str1'
  str2: string = 'str2'

  build() {
    Column() {
      Text(this.str1)
      Text(this.str2)
    }
  }
}

实践-购物车

结合前面学的布局知识,和今天的交互、状态管理实现一个移动端商城的购物车。可以点击商品的+、-来为购物车添加商品。

typescript 复制代码
interface Commodity {
  img: Resource,
  name: string,
  introduce: string,
  oldPrice: number,
  price: number,
  num: number,
}

@Entry
@Component
struct Index {
  @State Dog:Commodity={
    img: $r('app.media.test2'), // 商品图片资源
    name: '狗头', // 商品名称
    introduce: '这是一个滑稽的狗头', // 商品介绍
    oldPrice: 99, // 商品原价
    price: 9.9, // 商品现价
    num: 0, // 商品数量
  }

  build() {
    Column() {
      // 滚动视图
      Scroll(){
        Row(){
          // 商品图片
          Image(this.Dog.img)
            .size({
              width: 120,
              height: 80
            })
            .borderRadius(10)
            .margin({
              right: 10
            })
          
          // 商品信息列
          Column(){
            // 商品名称
            Row(){
              Text(this.Dog.name)
                .fontSize(18)
                .fontColor('#333')
            }
            // 商品介绍
            Row(){
              Text(this.Dog.introduce)
                .fontSize(16)
                .fontColor('#aaa')
                .lineHeight(30)
            }
            // 商品价格与操作
            Row(){
              Text(`¥${this.Dog.price}`)
                .fontSize(22)
                .fontWeight(FontWeight.Bold)
                .fontColor(Color.Red)
              
              Text(`¥${this.Dog.oldPrice}`)
                .fontSize(18)
                .fontColor('#999')
                .margin({left: 10})
                .decoration({
                  type: TextDecorationType.LineThrough
                })
              
              // 增加商品数量按钮
              Text('+')
                .width(15)
                .height(20)
                .margin({
                  left:30
                })
                .border({
                  width: 1,
                  color: '#aaa',
                  style: BorderStyle.Solid,
                  radius: {
                    topLeft:3,
                    bottomLeft:3
                  }
                })
                .fontColor('#333')
                .fontSize(16)
                .fontWeight(FontWeight.Bold)
                .textAlign(TextAlign.Center)
                .onClick(()=>{
                  this.Dog.num++
                })
              
              // 显示商品数量
              Text(this.Dog.num+'')
                .height(20)
                .border({
                  width: 1,
                  color: '#aaa',
                  style: BorderStyle.Solid,
                })
                .padding({
                  left: 5,
                  right: 5
                })
              
              // 减少商品数量按钮
              Text('-')
                .width(15)
                .height(20)
                .border({
                  width: 1,
                  color: '#aaa',
                  style: BorderStyle.Solid,
                  radius: {
                    topRight:3,
                    bottomRight:3
                  }
                })
                .fontColor('#333')
                .fontSize(16)
                .fontWeight(FontWeight.Bold)
                .textAlign(TextAlign.Center)
                .onClick(()=>{
                  if(this.Dog.num >= 1)
                    this.Dog.num--
                })
            }
          }
          .alignItems(HorizontalAlign.Start)
          .layoutWeight(1) // 设置列布局的权重
        }
        .alignItems(VerticalAlign.Top)
        .width('100%')
        .backgroundColor('#ddd')
        .padding(20)
      }
      .backgroundColor('#eee')
      .align(Alignment.Top)
      .layoutWeight(1) // 设置滚动视图的布局权重
      
      // 底部结算栏
      Row(){
        Column(){
          // 选购数量与总价
          Row(){
            Text(`已选${this.Dog.num}}件,`)
              .fontColor('#666')
            Text('合计:')
            Text(`¥${this.Dog.num * this.Dog.price}`)
              .fontColor(Color.Red)
          }
          // 显示优惠金额
          Row(){
            Text(`共减¥${(this.Dog.oldPrice - this.Dog.price) * this.Dog.num}`)
              .fontSize(14)
              .lineHeight(18)
              .fontColor(Color.Red)
          }
        }
        .alignItems(HorizontalAlign.End)
        .layoutWeight(1)
        
        // 结算按钮
        Button('结算外卖')
          .margin({
            left: 20
          })
      }
      .height(100)
      .padding(20)
      .backgroundColor(Color.White)
      .width('100%')
    }
  }
}

点击加号可以添加货物

相关推荐
知识分享小能手1 天前
React学习教程,从入门到精通, React 属性(Props)语法知识点与案例详解(14)
前端·javascript·vue.js·学习·react.js·vue·react
茯苓gao1 天前
STM32G4 速度环开环,电流环闭环 IF模式建模
笔记·stm32·单片机·嵌入式硬件·学习
爱笑的眼睛111 天前
HarmonyOS 应用开发新范式:深入探索 Stage 模型与 ArkUI 声明式开发
华为·harmonyos
是誰萆微了承諾1 天前
【golang学习笔记 gin 】1.2 redis 的使用
笔记·学习·golang
DKPT1 天前
Java内存区域与内存溢出
java·开发语言·jvm·笔记·学习
aaaweiaaaaaa1 天前
HTML和CSS学习
前端·css·学习·html
看海天一色听风起雨落1 天前
Python学习之装饰器
开发语言·python·学习
speop1 天前
llm的一点学习笔记
笔记·学习
非凡ghost1 天前
FxSound:提升音频体验,让音乐更动听
前端·学习·音视频·生活·软件需求
ue星空1 天前
月2期学习笔记
学习·游戏·ue5