• 【鸿蒙】第2天・装饰器・组件和页面生命周期


    官方文档:ForEach:循环渲染

    [Q&A] ForEach作用

    ForEach接口基于数组类型数据来进行循环渲染

    首次渲染

    @Entry
    @Component
    struct PracExample {
      @State list: Array<string> = ['one', 'two', 'three'];
    
      build() {
          Column() {
            ForEach(this.list, (item: string) => {ChildItem({ value: item })}, (item: string) => item)
          }.width('100%').height('30%').backgroundColor(Color.Pink)
      }
    }
    
    @Component
    struct ChildItem {
      @Prop value: string;
    
      build() {
        Text(this.value).fontSize(30).backgroundColor(Color.Orange)
      }
    }
    

    在这里插入图片描述

    注意体会ForEach第3个参数:有种hash的感觉

      @State list: Array<string> = ['one', 'two', 'two', 'three'];
    
      build() {
          Column() {
            ForEach(this.list, (item: string) => {ChildItem({ value: item })}, (item: string) => item)
          }.width('100%').height('30%').backgroundColor(Color.Pink)
      }
    

    在这里插入图片描述

      @State list: Array<string> = ['one', 'two', 'two', 'three'];
    
      build() {
          Column() {
            ForEach(this.list, (item: string) => {ChildItem({ value: item })}, (item: string) => "1")
          }.width('100%').height('30%').backgroundColor(Color.Pink)
      }
    

    在这里插入图片描述

      @State list: Array<string> = ['one', 'two', 'two', 'three'];
    
      build() {
          Column() {
            ForEach(this.list, (item: string) => {ChildItem({ value: item })}, (item: string) => item.length.toString())
          }.width('100%').height('30%').backgroundColor(Color.Pink)
      }
    

    在这里插入图片描述

    @State list: Array<string> = ['one', 'two', 'three'];
    
    build() {
      Column() {
        Button() {
          Text('在第1项后插入新项').fontSize(30)
        }
        .onClick(() => {
          this.list.push('new item');
        })
        ForEach(this.list, (item: string) => {ChildItem({ value: item })}, (item: string, index: number) => index.toString())
      }.width('100%').height('30%').backgroundColor(Color.Pink)
    }
    

    在这里插入图片描述

    非首次渲染

    @Entry
    @Component
    struct PracExample {
      @State simpleList: Array<string> = ['one', 'two', 'three'];
    
      build() {
          Column() {
            Text('点击修改第3个数组项的值').fontSize(24).fontColor(Color.Red)
              .onClick(() => {
                this.simpleList[2] = 'new three';
              })
    
            ForEach(this.simpleList, (item: string) => {ChildItem({ item: item })}, (item: string) => item)
          }.justifyContent(FlexAlign.Start).width('100%').height('100%')
      }
    }
    
    @Component
    struct ChildItem {
      @Prop item: string;
    
      build() {
        Text(this.item).fontSize(30)
      }
    }
    

    在这里插入图片描述

    键值one和two在上次渲染中已经存在,所以 ForEach 复用了对应的组件并进行了渲染。对于第三个数组项 “new three”,由于其通过键值生成规则 item 生成的键值new three在上次渲染中不存在,因此 ForEach 为该数组项创建了一个新的组件。

    数据源不变

    在数据源保持不变的场景中,数据源可以直接采用基本数据类型。

    @Entry
    @Component
    struct PracExample {
      @State list: Array<number> = [1, 2, 3, 4, 5];
    
      build() {
        Column() {
          ForEach(this.list, (item: number) => {ArticleSkeletonView().margin({ top: 20 })}, (item: number) => item.toString())
        }.padding(20).width('100%').height('100%')
      }
    }
    
    @Builder
    function textArea(width: number | Resource | string = '100%', height: number | Resource | string = '100%') {
      Row().width(width).height(height).backgroundColor(Color.Pink)
    }
    
    @Component
    struct ArticleSkeletonView {
      build() {
        Row() {
          Column() {
            textArea(80, 80)
          }.margin({ right: 20 })
    
          Column() {
            textArea('60%', 20)
            textArea('50%', 20)
          }.alignItems(HorizontalAlign.Start).justifyContent(FlexAlign.SpaceAround).height('100%')
        }.padding(20).borderRadius(12).backgroundColor(Color.Orange).height(120).width('100%').justifyContent(FlexAlign.SpaceBetween)
      }
    }
    

    在这里插入图片描述

    数据源数组项发生变化

    不要贪多,仅需理解ForEach和push思路即可,别的用法后续消化

    class Article {
      id: string;
      title: string;
      brief: string;
    
      constructor(id: string, title: string, brief: string) {
        this.id = id;
        this.title = title;
        this.brief = brief;
      }
    }
    
    @Entry
    @Component
    struct PracExample {
      @State isListReachEnd: boolean = false;
      @State articleList: Array<Article> = [
        new Article('001', '第1篇文章', '文章简介内容'),
        new Article('002', '第2篇文章', '文章简介内容'),
        new Article('003', '第3篇文章', '文章简介内容'),
        new Article('004', '第4篇文章', '文章简介内容'),
        new Article('005', '第5篇文章', '文章简介内容'),
        new Article('006', '第6篇文章', '文章简介内容')
      ]
    
      loadMoreArticles() {
        this.articleList.push(new Article('007', '加载的新文章', '文章简介内容'));
      }
    
      build() {
        Column({ space: 5 }) {
          List() {
            ForEach(this.articleList, (item: Article) => {
              ListItem() {
                ArticleCard({ article: item }).margin({ top: 20 })
              }
            }, (item: Article) => item.id)
          }.onReachEnd(() => {
            this.isListReachEnd = true;
          })
          .parallelGesture(
            PanGesture({ direction: PanDirection.Up, distance: 80 })
              .onActionStart(() => {
                if (this.isListReachEnd) {
                  this.loadMoreArticles();
                  this.isListReachEnd = false;
                }
              })
          ).padding(20).scrollBar(BarState.Off)
        }.width('100%').height('100%').backgroundColor(0xF1F3F5)
      }
    }
    
    @Component
    struct ArticleCard {
      @Prop article: Article;
    
      build() {
        Row() {
          Image($r('app.media.icon')).width(80).height(80).margin({ right: 20 })
    
          Column() {
            Text(this.article.title).fontSize(20).margin({ bottom: 8 })
            Text(this.article.brief).fontSize(16).fontColor(Color.Gray).margin({ bottom: 8 })
          }.alignItems(HorizontalAlign.Start).width('80%').height('100%')
        }.padding(20).borderRadius(12).backgroundColor(Color.Pink).height(120).width('100%').justifyContent(FlexAlign.SpaceBetween)
      }
    }
    

    数据源数组项子属性变化

    不要贪多,仅需理解ForEach即可

    @Observed
    class Article {
      id: string;
      title: string;
      brief: string;
      isLiked: boolean;
      likesCount: number;
    
      constructor(id: string, title: string, brief: string, isLiked: boolean, likesCount: number) {
        this.id = id;
        this.title = title;
        this.brief = brief;
        this.isLiked = isLiked;
        this.likesCount = likesCount;
      }
    }
    
    @Entry
    @Component
    struct PracExample {
      @State articleList: Array<Article> = [
        new Article('001', '第0篇文章', '文章简介内容', false, 100),
        new Article('002', '第1篇文章', '文章简介内容', false, 100),
        new Article('003', '第2篇文章', '文章简介内容', false, 100),
        new Article('004', '第4篇文章', '文章简介内容', false, 100),
        new Article('005', '第5篇文章', '文章简介内容', false, 100),
        new Article('006', '第6篇文章', '文章简介内容', false, 100),
      ];
    
      build() {
        List() {
          ForEach(this.articleList, (item: Article) => {ListItem() {ArticleCard({ article: item }).margin({ top: 20 })}}, (item: Article) => item.id)
        }.padding(20).scrollBar(BarState.Off).backgroundColor(0xF1F3F5)
      }
    }
    
    @Component
    struct ArticleCard {
      @ObjectLink article: Article;
    
      handleLiked() {
        this.article.isLiked = !this.article.isLiked;
        this.article.likesCount = this.article.isLiked ? this.article.likesCount + 1 : this.article.likesCount - 1;
      }
    
      build() {
        Row() {
          Image($r('app.media.icon')).width(80).height(80).margin({ right: 20 })
    
          Column() {
            Text(this.article.title).fontSize(20).margin({ bottom: 8 })
            Text(this.article.brief).fontSize(16).fontColor(Color.Gray).margin({ bottom: 8 })
    
            Row() {
              Image(this.article.isLiked ? $r('app.media.startIcon') : $r('app.media.icon')).width(24).height(24).margin({ right: 8 })
              Text(this.article.likesCount.toString()).fontSize(16)
            }.justifyContent(FlexAlign.Center)
            .onClick(() => this.handleLiked())
    
          }.alignItems(HorizontalAlign.Start).width('80%').height('100%')
        }.padding(20).borderRadius(12).backgroundColor('#FFECECEC').height(120).width('100%').justifyContent(FlexAlign.SpaceBetween)
      }
    }
    
  • 相关阅读:
    mysql的变量
    十四、Qt主机信息与网络编程
    Typora 自定义样式(mac 风代码块、引用块、加粗、高亮、图片默认居左、行内代码)
    华为od机考题目-导师请吃火锅
    应届生写简历不如AI?HR招人到底看什么
    python+requests+pytest+allure自动化框架
    Python学习:基本数据类型
    更新SQLite数据库数据
    为什么要学Selenium自动化测试?
    react native 使用阿里字体图标库
  • 原文地址:https://blog.csdn.net/weixin_37646636/article/details/140021676