加载中...
返回

【HarmonyOS learning】【2】带跳转的待办列表

note1 一样,还是对着Demo自己敲一遍代码;不过考虑到TodoList太简单(相比于第一个Demo),决定结合后面章节的 router 相关知识点,做一点个性化的扩展。

1 准备

有了 note1 对ArkTs的细致剖析,实际上这个 todolist 的Demo难度远小于第一个Demo。

下载项目源码,完成若干文件的拷贝:

  • src/main/ets/viewmodel ——数据源,没有改动的空间

  • src/main/ets/common ——一些常量定义,没有改动的空间

  • src/main/resources/base ——资源文件,重要,有改动空间但没必要改动……(比如想给自己的待办项换个图标)

2 TodoItem

照着Demo实现待办项即可:

import CommonConstants from '../common/constant/CommonConstant'

@Component
export default struct TodoItem {
  private content?: string
  @State done: boolean = false;

  @Builder labelIcon(icon: Resource) {
    Image(icon)
      .objectFit(ImageFit.Contain)
      .width($r('app.float.checkbox_width'))
      .height($r('app.float.checkbox_width'))
      .margin($r('app.float.checkbox_margin'))
  }

  build() {
    Row() {
      if (this.done) {
        this.labelIcon($r('app.media.ic_ok'))
      } else {
        this.labelIcon($r('app.media.ic_default'))
      }

      Text(this.content)
        // ===== snip =====
    }
    // ===== snip =====
    .onClick(() => {
      this.done = !this.done
    })
  }
}

关键部分只是一个条件渲染,用于在不同的完成状态选择不同的图标,这个在 note 1 已经接触过了。

3 完成所有任务时使用Router

根据官网教程顺序,TodoList后面就是应用程序框架 UIAbility ,有个页面跳转的 Demo ,令我萌生想把TodoList跟这个Demo结合起来的想法。

容易想到,对于待办列表这个页面来说,当所有任务完成时,跳转到一个祝贺页面,是常见、简单且合理的场景。

于是做如下实现。

3.1 未完成项数统计

要在所有任务完成时进行页面跳转,首先应能够统计未完成的项数。

这里就适合使用 @Link 装饰器,将父子元素双向绑定,父元素(即总页面)提供总的待办任务数,每个子元素( TodoItem )在被点为完成时将此未完成项数减一。

Talk is Cheap:

@Component
export default struct TodoItem {
  private content?: string
  @State done: boolean = false;
  @Link unfinishedTasks: number;
  build() {
    Row() {
     // ===== snip =====
    .onClick(() => {
      this.done = !this.done
      if (this.done) {
        this.unfinishedTasks -= 1;
      } else {
        this.unfinishedTasks += 1;
      }
    })
  }
}

Index页面:

@Entry
@Component
struct Index {
  private totalTasks: Array<string> = [];
  @State @Watch('onTaskCountChange') unfinishedTasks: number = 0;
  @State msg: string = '';

  onTaskCountChange(propName: string): void {
    this.msg = "toggle " + this.unfinishedTasks;
    if (this.unfinishedTasks === 0) {
      router.pushUrl({
        url: 'pages/Congrats',
        params: { count: this.totalTasks.length }
      }).catch((error: Error) => {
        this.msg = 'error: ' + JSON.stringify(error);
      });
    }
  }

  aboutToAppear() {
    this.totalTasks = DataModel.getData();
    this.unfinishedTasks = this.totalTasks.length;
  }

  build() {
    Column({ space: CommonConstants.COLUMN_SPACE }) {
      Text($r('app.string.page_title'))
        // ===== snip =====
      Text(this.msg)
        .textAlign(TextAlign.Center)

      ForEach(this.totalTasks, (item: string) => {
        TodoItem({ content: item, unfinishedTasks: $unfinishedTasks });
      }, (item: string) => JSON.stringify(item))
    }
    // ===== snip =====
  }
}

这里关注 unfinishedTasks 这个变量,它和 @Link 的双向绑定,也是前一节中遇到过的。

3.2 未完成项数监控

能够实时更新未完成项数之后,还有一个重要的任务就是 当这个项数减为 0 时,要进行页面跳转 ,这里,通过 @Watch('[callback]') 装饰器,实现对这个变量的动态监控。

  @State @Watch('onTaskCountChange') unfinishedTasks: number = 0;

  onTaskCountChange(propName: string): void {
    this.msg = "toggle " + this.unfinishedTasks;
    if (this.unfinishedTasks === 0) {
      router.pushUrl({
        url: 'pages/Congrats',
        params: { count: this.totalTasks.length }
      }).catch((error: Error) => {
        this.msg = 'error: ' + JSON.stringify(error);
      });
    }
  }

每次这个变量发生变化时(在这里就是由子元素触发的变化),系统会调用一次回调函数,在函数中,我们判断这个变量的值是否减至 0 ,若是,执行页面跳转。

3.3 页面跳转

页面跳转的部分,就完全是 Demo 的复刻。我们提供一个 Congrats.ets 页面,跳转时向它传递完成的任务总数,在页面中获取参数并打印出来。

@Entry
@Component
struct Congrats {
  private count?: string = (router.getParams() as Record<string, string>)['count'];
  build() {
    Row() {
      Column() {
        Text('Great! U have finished ' + this.count + " tasks!")
          .fontSize('38fp')
          .textAlign(TextAlign.Center)
          .padding({ left: 0.5 })

        Blank()

        Button('ok')
          .fontSize('16fp')
          .width('260vp')
          .height('40vp')
          .backgroundColor('#007DFF')
          .onClick(() => {
            router.back();
          })
      }
      .width('100%')
      .height('100%')
    }
  }
}

4 结果

第二个页面没有样式设计,凑合看~

10 comments
Anonymous
Markdown is supported
@mpv945
mpv945commentedabout 3 years ago

添加图片,如果使用外部图床的http链接 。图片无法点击放大,你那边怎么解决的?

@SGS4ever
SGS4evercommentedabout 3 years ago

@mpv945
添加图片,如果使用外部图床的http链接 。图片无法点击放大,你那边怎么解决的?

我的博客没有使用图床,所以没办法帮到你~

@Celetherin
Celetherincommentedalmost 3 years ago

您好,我也是使用的stack主题,我在照着您的方法添加返回顶部按钮时,遇到了按钮虽然出现、也能够点击,但无法实现实际上的返回顶部功能的问题,我没有任何的代码知识,不知道您有没有解决方法?
另外,也是想提醒一下其他需要这篇教程的朋友,最新版的stack主题,添加返回按钮的组件应该在layouts/partials/sidebar/right.html, 在layouts/_default/single.html中添加代码会导致出现两个右边栏。

@jsjcjsjc
jsjcjsjccommentedalmost 3 years ago

请教一下博主,如何优雅的给stack主题添加广告哈?
我只想在左或者右侧边栏底部,或者每篇文章底部添加一个小小的广告,但是默认似乎的满屏广告哈~~
感谢

@SGS4ever
SGS4evercommentedalmost 3 years ago
@ClimbingMouse
ClimbingMousecommentedover 2 years ago

你好,按照你的方法设置页面载入动画,这个动画不会停止咋办啊

@46fafa
46fafacommentedover 2 years ago

博主你好,请问一下主页布局修改哪里的代码如何作用于整个网页,我发现修改后的布局只存在主页和前两篇文章,其他部分还是没修改的样子

@4kohakunushi
4kohakunushicommentedalmost 2 years ago

你好,关于左侧栏图标高亮我这里存在一些问题想请教你。我取消了原本主页直接抓取post的内容在中间显示的版块,这个部分改成了其他东西,与此同时新增了一个抓取post信息的与links、search等目录并列的一个目录,现在的问题是这些部分虽然都能正常显示,但是对应的抓取post的那个目录无法选中以后高亮,应该修改增加什么才能让它也可以选中后高亮呢?

@SGS4ever
SGS4evercommentedalmost 2 years ago

首先我只能基于本文使用的Stack版本来尝试解答,因为没看过当前的Stack主题的代码~
我重新翻了下此前写的关于高亮的内容,理论上只要你的post页面的标题在menu配置中即可高亮。如果post页面是你站点的根路径,那应该可以参考我的文章里写的方法,修改下active的触发逻辑~

@4kohakunushi
你好,关于左侧栏图标高亮我这里存在一些问题想请教你。我取消了原本主页直接抓取post的内容在中间显示的版块,这个部分改成了其他东西,与此同时新增了一个抓取post信息的与links、search等目录并列的一个目录,现在的问题是这些部分虽然都能正常显示,但是对应的抓取post的那个目录无法选中以后高亮,应该修改增加什么才能让它也可以选中后高亮呢?

@sansan-cc
sansan-cccommented6 months ago

感谢博主的建站帖子,有很大的帮助。

有朋自远方来,不亦说乎?