【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%')
    }
  }
}

点击加号可以添加货物

相关推荐
两水先木示20 分钟前
【Unity3D】ECS入门学习(六)状态组件 ISystemStateComponentData
学习·unity·ecs
JasonYin~1 小时前
HarmonyOS NEXT 实战之元服务:静态案例效果---我的快递查询
harmonyos
Jillyli1 小时前
气相色谱-质谱联用分析方法中的常用部件,分流平板更换
科技·学习·其他·电脑
找了一圈尾巴1 小时前
Wend看源码-Java-集合学习(List)
java·学习
莫奈的日出2 小时前
PS等软件学习笔记
笔记·学习·ps/pr学习笔记
爱编程的小新☆2 小时前
不良人系列-复兴数据结构(二叉树)
java·数据结构·学习·二叉树
Y.O.U..3 小时前
Mysq学习-Mysql查询(4)
数据库·学习·mysql
深海的鲸同学 luvi5 小时前
【HarmonyOS NEXT】鸿蒙原生应用“上述”
华为·harmonyos
play_big_knife5 小时前
鸿蒙项目云捐助第二十八讲云捐助项目首页组件云数据库加载轮播图
数据库·华为·harmonyos·鸿蒙·云开发·鸿蒙开发·鸿蒙技术
B1nna10 小时前
Redis学习(三)缓存
redis·学习·缓存