加载中...
返回

【HarmonyOS learning】【3】Arkts组件

本篇主要分析 常用组件与布局 这个案例,这个 Demo 主要是Ark UI的使用,没有太多新的概念,就不再手动复现了。摘一些知识点记录一下。

1 登录页面

1.1 定时器

// src/main/ets/pages/LoginPage.ets
login(): void {
  if (this.account === '' || this.password === '') {
    prompt.showToast({
      message: $r('app.string.input_empty_tips')
    })
  } else {
    this.isShowProgress = true;
    if (this.timeOutId === -1) {
      this.timeOutId = setTimeout(() => {
        this.isShowProgress = false;
        this.timeOutId = -1;
        router.replaceUrl({ url: 'pages/MainPage' });
      }, CommonConstants.LOGIN_DELAY_TIME);
    }
  }
}

aboutToDisappear() {
  clearTimeout(this.timeOutId);
  this.timeOutId = -1;
}

这是登录页面实现的功能逻辑,这里首次出现了 setTimeout 这个动作,然后把函数返回值保存到本地变量 timeOutId ,在 aboutToDisappear 的时候调用 clearTimeout 删除定时器。

1.2 @Extend装饰器

@Extend 装饰器用来简化重复的样式代码,效果还是比较显著的,比如Demo里用来装饰登录页面输入框和分割线的函数:

@Extend(TextInput)
function inputStyle() {
  .placeholderColor($r('app.color.placeholder_color'))
  .height($r('app.float.login_input_height'))
  .fontSize($r('app.float.big_text_size'))
  .backgroundColor($r('app.color.background'))
  .width(CommonConstants.FULL_PARENT)
  .padding({ left: CommonConstants.INPUT_PADDING_LEFT })
  .margin({ top: $r('app.float.input_margin_top') })
}

@Extend(Line)
function lineStyle() {
  .width(CommonConstants.FULL_PARENT)
  .height($r('app.float.line_height'))
  .backgroundColor($r('app.color.line_color'))
}

以及他们的使用,达到了简化代码的目的:

TextInput({ placeholder: $r('app.string.account') })
  .maxLength(CommonConstants.INPUT_ACCOUNT_LENGTH)
  .type(InputType.Number)
  .inputStyle()
  .onChange((value: string) => {
    this.account = value;
  })
Line().lineStyle()

TextInput({ placeholder: $r('app.string.password') })
  .maxLength(CommonConstants.INPUT_PASSWORD_LENGTH)
  .type(InputType.Password)
  .inputStyle()
  .onChange((value: string) => {
    this.password = value;
  })
Line().lineStyle()

1.3 LoadingProgress组件

LoadingProgress 组件就纯粹是语言糖了。

逆天远程仿真设备,一下午没刷出一个可用的,没看到这个组件的实际效果。

2 主页

2.1 Tab

主页也是有页面跳转的,但不同于登录跳转到主页用的 router ,这里通过 tabs 实现主页面和设置页面的两个不同页面的转换。

@Entry
@Component
struct MainPage {
  @State currentIndex: number = CommonConstants.HOME_TAB_INDEX;
  private tabsController: TabsController = new TabsController();

  @Builder TabBuilder(title: string, index: number, selectedImg: Resource, normalImg: Resource) {
    Column() {
      Image(this.currentIndex === index ? selectedImg : normalImg)
        .width($r('app.float.mainPage_baseTab_size'))
        .height($r('app.float.mainPage_baseTab_size'))
      Text(title)
        .margin({ top: $r('app.float.mainPage_baseTab_top') })
        .fontSize($r('app.float.main_tab_fontSize'))
        .fontColor(this.currentIndex === index ? $r('app.color.mainPage_selected') : $r('app.color.mainPage_normal'))
    }
    .justifyContent(FlexAlign.Center)
    .height($r('app.float.mainPage_barHeight'))
    .width(CommonConstants.FULL_PARENT)
    .onClick(() => {
      this.currentIndex = index;
      this.tabsController.changeIndex(this.currentIndex);
    })
  }
 
  build() {
    Tabs({
      barPosition: BarPosition.End,
      controller: this.tabsController
    }) {
      TabContent() {
        Home()
      }
      .padding({ left: $r('app.float.mainPage_padding'), right: $r('app.float.mainPage_padding') })
      .backgroundColor($r('app.color.mainPage_backgroundColor'))
      .tabBar(this.TabBuilder(CommonConstants.HOME_TITLE, CommonConstants.HOME_TAB_INDEX,
        $r('app.media.home_selected'), $r('app.media.home_normal')))

      TabContent() {
        Setting()
      }
      .padding({ left: $r('app.float.mainPage_padding'), right: $r('app.float.mainPage_padding') })
      .backgroundColor($r('app.color.mainPage_backgroundColor'))
      .tabBar(this.TabBuilder(CommonConstants.MINE_TITLE, CommonConstants.MINE_TAB_INDEX,
        $r('app.media.mine_selected'), $r('app.media.mine_normal')))
    }
    .width(CommonConstants.FULL_PARENT)
    .backgroundColor(Color.White)
    .barHeight($r('app.float.mainPage_barHeight'))
    .barMode(BarMode.Fixed)
    .onChange((index: number) => {
      this.currentIndex = index;
    })
  }
}

有若干知识点值得分析:

  • 实际页面是通过 TabContent 来呈现的,每个页面又有自己对应的 tabBar

  • tabBar 内部调用 @Builder 函数来创建了一个列元素;列元素又用选择渲染来对激活状态下的标签进行特殊呈现;

  • tabBar 内部对是否激活的判断,实际上是通过父组件的一个 @State 变量来维护的,同时每个 tabBaronClick 方法又会激活不同的页面,并改变父组件的 currentIndex

2.2 Swiper & Grid

主页第一个 TabContentHome 组件,这个组件最吸引眼球的地方大概是 Swiper

轮播组件是很多需求场景里必不可少的东西,极适合在首页展示主题相关的内容。在这里 Swiper 实际上就是个语言糖,遥想当年拿HTML三剑客哼哧哼哧实现的土鳖轮播效果现在居然都已经框架内嵌了……

用法还是比较简单的:

Swiper(this.swiperController) {
  ForEach(mainViewModel.getSwiperImages(), (img: Resource) => {
    Image(img).borderRadius($r('app.float.home_swiper_borderRadius'))
  }, (img: Resource) => JSON.stringify(img.id))
}
.autoPlay(true)

Grid 用于创建网格,此次Demo里的网格属于比较老实的款式,文档当中给出 GridItem.rowStart/rowEnd/columnStart/columnEnd 的示例,展示了网格的灵活性。

Grid() {
  ForEach(mainViewModel.getFirstGridData(), (item: ItemData) => {
    GridItem() {
      Column() {
        Image(item.img)
          .width($r('app.float.home_homeCell_size'))
          .height($r('app.float.home_homeCell_size'))
        Text(item.title)
          .fontSize($r('app.float.little_text_size'))
          .margin({ top: $r('app.float.home_homeCell_margin') })
      }
    }
  }, (item: ItemData) => JSON.stringify(item))
}
.columnsTemplate('1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr')
.columnsGap($r('app.float.home_grid_columnsGap'))
.rowsGap($r('app.float.home_grid_rowGap'))
10 comments
Anonymous
Markdown is supported
@mpv945
mpv945commentedalmost 3 years ago

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

@SGS4ever
SGS4evercommentedalmost 3 years ago

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

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

@Celetherin
Celetherincommentedover 2 years ago

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

@jsjcjsjc
jsjcjsjccommentedover 2 years ago

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

@SGS4ever
SGS4evercommentedover 2 years ago
@ClimbingMouse
ClimbingMousecommentedabout 2 years ago

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

@46fafa
46fafacommentedabout 2 years ago

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

@4kohakunushi
4kohakunushicommentedover 1 year ago

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

@SGS4ever
SGS4evercommentedover 1 year ago

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

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

@sansan-cc
sansan-cccommented3 months ago

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

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