一个简单的小开发
首页
分类
标签
归档
关于

YDS

30岁大龄程java程序员,心不老,神不灭
首页
分类
标签
归档
关于
  • vue项目设置-vscode
  • 在github的pages上部署一个vue3的项目
  • vue3部署githubpages问题汇总
  • 鸿蒙app开发中的数据驱动ui渲染问题
    • 有趣的同事
    • 他的问题
    • 复盘一下
  • JS
yds
2024-08-01
目录

鸿蒙app开发中的数据驱动ui渲染问题

# 有趣的同事

我有一个年轻的同事,小哥帅的一批,他最近在学习鸿蒙手机app开发,据他据说,他已经参照华为官网的教程学习了有半个月了,可以说是已经大成,我听此很为他感到开心。但是他说在开发的过程中遇到一个问题,就是使用数组数据循环渲染页面时,改动某个元素的属性,页面不会跟着发生变化。他在在网上找了两天了,一直没有找到解决方案,最终他听从了网友大神的建议,某个元素的属性需要变化时,就将这个元素删掉,然后重新添加一个元素进去,因为定义数组的时候用了@State来修饰,所以页面是可以跟着变化的,他照做了,完事后功能已经非常完美了,但美中不足的是,每次操作元素时,列表项中有个图标,它都会闪一下,这是他的问题。

我听完,心想,原因大概也不难猜,毕竟他删除了元素重新插入的,顺序没有乱就已经很不错了。毕竟我也是精通vue的大佬,这不就是双向绑定、数据驱动页面元素嘛,按理说华子出品的开发语言不能连这种基础的功能都做不到吧,我的同事告诉我,现在全网并没有解决方案。我说:“我不信,我给你写个demo吧。”此时,我历史学习鸿蒙的总时长累计应该有1个小时左右,其中40分钟应该是安装环境。

# 他的问题

他的写法是这样的(我没仔细看过他的代码,但大致是这样的结构)

@Entry
@Component
struct Index {

  // 假装这是接口请求来的数据
  @State myList: Array<any> = [
    {id: 1, imgUrl: $r('app.media.bg_1'), title: '标题标题', brief: '内容内容内容内容内容', num: 0},
    {id: 2, imgUrl: $r('app.media.bg_1'), title: '标题标题', brief: '内容内容内容内容内容', num: 0},
    {id: 3, imgUrl: $r('app.media.bg_1'), title: '标题标题', brief: '内容内容内容内容内容', num: 0}
  ]

  build() {
    Column() {
      ForEach(
        this.myList,
        (item: any, index: number) => {
          Row() {
            Image(item.imgUrl)
              // ...
            Column() {
              Text(item.id + ": " + item.title)
                // ...
              Text(item.brief)
                // ...
            }
            // ...
            Text(item.num+"")
          }
          // ...
          .onClick(() => {
            item.num++;
            console.log("触发了点击,第" + index + "个元素的num-->" + this.myList[index].num + "");
          })
        },
        (index: number) => index+""
      )
    }
    // ...
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

所以这段代码显示的页面应该是这个样子的

当点击每一行的时候,日志也有输出

08-02 12:13:41.605 32241-6026747 I A0c0d0/JSApp: app Log: 触发了点击,第0个元素的num-->1
08-02 12:13:42.824 32241-6026747 I A0c0d0/JSApp: app Log: 触发了点击,第0个元素的num-->2
08-02 12:13:43.820 32241-6026747 I A0c0d0/JSApp: app Log: 触发了点击,第0个元素的num-->3
08-02 12:13:49.187 32241-6026747 I A0c0d0/JSApp: app Log: 触发了点击,第1个元素的num-->1
08-02 12:13:49.888 32241-6026747 I A0c0d0/JSApp: app Log: 触发了点击,第1个元素的num-->2
08-02 12:13:51.887 32241-6026747 I A0c0d0/JSApp: app Log: 触发了点击,第2个元素的num-->1
08-02 12:13:52.655 32241-6026747 I A0c0d0/JSApp: app Log: 触发了点击,第2个元素的num-->2
08-02 12:16:03.355 32241-6026747 I A0c0d0/JSApp: app Log: 触发了点击,第2个元素的num-->3
08-02 12:16:03.556 32241-6026747 I A0c0d0/JSApp: app Log: 触发了点击,第2个元素的num-->4
08-02 12:16:03.755 32241-6026747 I A0c0d0/JSApp: app Log: 触发了点击,第2个元素的num-->5
08-02 12:16:03.922 32241-6026747 I A0c0d0/JSApp: app Log: 触发了点击,第2个元素的num-->6
1
2
3
4
5
6
7
8
9
10
11

但是页面是并没有发生任何变化,我们期望的是第一行后面的那个数据能发生变化,毕竟我们在onclick中修改了num的值。

这个现象让我想到了vue中的ref()和reactive()的区别,那么这里可能也是相同的问题,我写demo的时候,是这样写的

@Entry
@Component
struct Index {
  // 假装这是接口请求来的数据
  @State myList: Array<any> = [ ... ]

  build() {
    Column() {
      ForEach(
        this.myList,
        (item: any, index: number) => {
          DemoItem({item: item, index: index})
        },
        (index: number) => index+""
      )
    }
    // ...
  }
}

@Component
struct DemoItem {
  @Prop item: any;
  @Prop index: number;

  Row() {
    Image(item.imgUrl)
    Column() {
      Text(item.id + ": " + item.title)
      Text(item.brief)
    }
    Text(item.num+"")
  }
  .onClick(() => {
    item.num++;
    console.log("触发了点击,第" + index + "个元素的num-->" + this.myList[index].num + "");
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

现在这样的写法已经满足我的期望了:

我将这种方式告诉了我的同事,他也按我这种方式,将每一行拆分成独立的Component,但是他那边似乎并不好使,于是我又改了一版:

@Component
struct DemoItem {
  @Prop item: any;
  @Prop index: number;

  // 将复杂的对象解构出简单的属性变量
  @State title: string = this.item.title;
  @State brief: string = this.item.brief;
  @State num: number = this.item.num;

  // 在页面中引用基础数据类型的变量
}
1
2
3
4
5
6
7
8
9
10
11
12

到此,他的问题已经解决了。

# 复盘一下

我觉得他的问题并不在于没有学习明白,本质的问题应该是在于写代码时的代码布局习惯,他写的页面代码是一整大坨,页面中不管大的小的功能块都在一坨中,导到了不得不用更复杂的数据结构体来封装数据,而恰好@State的变量复杂对象属性驱动页面元素变化并不理想。
我写的代码,一开始就把列表按行来封装@Component了,每个@Component中不需要使用太复杂的对象结构,甚至直接用基本数据类型都行,因为足够小,每个块中不需要太多的属性变量,我没遇到他那样的问题,在我看来完全就是代码书写习惯的区别。好的代码书写习惯可以很自然的写出好的代码结构,同时也可以避免很多不必要的坑,修改起来也更容易。

#鸿蒙#app
上次更新: 2024/09/30, 01:34:11
vue3部署githubpages问题汇总

← vue3部署githubpages问题汇总

最近更新
01
使用docker-compose安装mysql
09-30
02
LINUX连接openvpn
07-02
03
MX-LINUX配置源
06-27
更多文章>
Theme by Vdoing | Copyright © 2020-2024 YDS
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式