当前位置: 代码网 > 手机>品牌>手机系统 > HarmonyOS简单的购物应用示例

HarmonyOS简单的购物应用示例

2024年08月02日 手机系统 我要评论
由于“首页”和“我的”页面中有多处图片和文字的组合,因此提取出ItemData类。在MainViewModel.ets文件中对页面使用的资源进行定义。MainViewModel代码case 0:breakcase 1:breakdefault:breakItemData代码/***//***//***/others?: Resource;

本示例主要包含:“登录”、“首页”、“我的”三个页面。

完整示例

harmonyos-ui: harmonyos一些ui示例 - gitee.com

软件要求

代码结构

  1. ├──entry/src/main/ets // 代码区
  2. │ ├──common
  3. │ │ └──constants
  4. │ │      └──commonconstants.ets // 公共常量类
  5. │ ├──entryability
  6. │ │ └──entryability.ts // 程序入口类
  7. │ ├──pages
  8. │ │ ├──login.ets // 登录界面
  9. │ │ └──mainpage.ets // 主界面
  10. │ ├──view
  11. │ │ ├──home.ets // 首页
  12. │ │ └──mime.ets // 我的
  13. │ └──viewmodel
  14. │ ├──itemdata.ets // 列表数据实体类
  15. │ └──mainviewmodel.ets // 主界面视图model
  16. └──entry/src/main/resources // 应用资源目录

实现“登录”页面

页面使用column容器组件布局,由image、text、textinput、button、loadingprogress等基础组件构成。

代码整体结构

@entry
@component
struct loginpage {
  ...
  build() {
    column() {
      image($r('app.media.logo'))
        ...
      text($r('app.string.login_page'))
        ...
      text($r('app.string.login_more'))
        ...
      textinput({ placeholder: $r('app.string.account') })
        ...
      textinput({ placeholder: $r('app.string.password') })
        ...
      button($r('app.string.login'), { type: buttontype.capsule })
        ...
      if (this.isshowprogress) {
        loadingprogress()
          ...
      }
      ...
    }
    ...
  }
}

获取用户输入

当用户登录前,需要获取用户输入的帐号和密码才能执行登录逻辑。给textinput设置onchange事件,在onchange事件里面实时获取用户输入的文本信息。

控制loadingprogress显示和隐藏

给登录按钮绑定onclick事件,调用login方法模拟登录。定义变量isshowprogress结合条件渲染if用来控制loadingprogress的显示和隐藏。当用户点击按钮时设置isshowprogress为true,即显示loadingprogress;使用定时器settimeout设置isshowprogress 2秒后为false,即隐藏loadingprogress,然后执行跳转到首页的逻辑。

实现页面跳转

页面间的跳转可以使用router模块相关api来实现,使用前需要先导入该模块,然后使用router.replaceurl()方法实现页面跳转。

login(): void {
    ...
    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);
    }  
  }

login完整代码

import prompt from '@system.prompt';
import router from '@ohos.router';
import commonconstants from '../common/constants/commonconstants'

@entry
@component
struct login {
  @state account: string = '';
  @state password: string = '';
  @state isshowprogress: boolean = false
  private timeoutid: number = -1

  @builder
  imagebutton(src: resource) {
    button({ type: buttontype.circle, stateeffect: true }) {
      image(src)
    }
    .height($r('app.float.other_login_image_size'))
    .width($r('app.float.other_login_image_size'))
    .backgroundcolor($r('app.color.background'))
    .margin({bottom:$r('app.float.other_login_margin_bottom')})
  }

  login(): void {
    if (this.account === '' || this.password === '') {
      prompt.showtoast({
        message: commonconstants.input_not_empty
      })
    } 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)
      }
    }
  }

  build() {
    column() {

      image($r('app.media.logo'))
        .width($r('app.float.logo_image_size'))
        .height($r('app.float.logo_image_size'))
        .margin({ top: $r('app.float.logo_margin_top'), bottom: $r('app.float.logo_margin_bottom') })
      text($r('app.string.login_module_desc_no'))
        .fontsize($r('app.float.page_title_text_size'))
        .fontweight(fontweight.medium)
        .fontcolor($r('app.color.login_text_color'))
      text($r('app.string.login_module_desc_de'))
        .fontsize($r('app.float.normal_text_size'))
        .fontweight(fontweight.medium)
        .fontcolor($r('app.color.login_more_text_color'))
        .margin({ bottom: $r('app.float.login_more_margin_bottom'), top: $r('app.float.login_more_margin_top') })

      textinput({ placeholder: $r('app.string.account') })
        .maxlength(commonconstants.input_account_length)
        .inputstyle()
        .onchange((value: string) => {
          this.account = value
        })
      line().linestyle()
      textinput({ placeholder: $r('app.string.password') })
        .maxlength(commonconstants.input_password_length)
        .inputstyle()
        .type(inputtype.password)
        .onchange((value: string) => {
          this.password = value
        })
      line().linestyle()
      row({ space: commonconstants.common_space_20 }) {
        text($r('app.string.message_login')).bluetextstyle()
        text($r('app.string.forgot_password')).bluetextstyle()
      }
      .justifycontent(flexalign.spacebetween)
      .width(commonconstants.page_width)

      button($r('app.string.login'), { type: buttontype.capsule })
        .width(commonconstants.button_width)
        .height($r('app.float.login_button_height'))
        .fontsize($r('app.float.normal_text_size'))
        .fontweight(fontweight.medium)
        .backgroundcolor($r('app.color.login_button_color'))
        .margin({ top: $r('app.float.login_button_margin_top'), bottom: $r('app.float.login_button_margin_bottom') })
        .onclick(() => {
          this.login()
        })
      text($r('app.string.register_account'))
        .fontcolor($r('app.color.login_blue_text_color'))
        .fontsize($r('app.float.normal_text_size'))
        .fontweight(fontweight.medium)
      if (this.isshowprogress) {
        loadingprogress()
          .color($r('app.color.loading_color'))
          .width($r('app.float.login_progress_size'))
          .height($r('app.float.login_progress_size'))
          .margin({ top: $r('app.float.login_progress_margin_top') })
      }

      blank()
      text($r('app.string.other_login_method'))
        .fontcolor($r('app.color.other_login_text_color'))
        .fontsize($r('app.float.little_text_size'))
        .fontweight(fontweight.medium)
        .margin({ top: $r('app.float.other_login_margin_top'), bottom: $r('app.float.other_login_margin_bottom') })

      row({ space: commonconstants.login_methods_space }) {
        this.imagebutton($r('app.media.login_method1'))
        this.imagebutton($r('app.media.login_method2'))
        this.imagebutton($r('app.media.login_method3'))
      }

    }
    .backgroundcolor($r('app.color.background'))
    .height(commonconstants.full_parent)
    .width(commonconstants.full_parent)
    .padding({
      left: $r('app.float.page_padding_hor'),
      right: $r('app.float.page_padding_hor'),
      bottom: $r('app.float.login_page_padding_bottom')
    })
  }
}

@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)
  .margin({ top: $r('app.float.input_margin_top') })
}

@extend(text) function bluetextstyle() {
  .fontcolor($r('app.color.login_blue_text_color'))
  .fontsize($r('app.float.small_text_size'))
  .fontweight(fontweight.medium)
  .margin({ top: $r('app.float.forgot_margin_top') })
}

@extend(line) function linestyle() {
  .width(commonconstants.full_parent)
  .height($r('app.float.line_height'))
  .backgroundcolor($r('app.color.line_color'))
}

实现“首页”和“我的”页面

本示例由两个tab页组成,使用tabs组件来实现,提取tabbar的公共样式,同时设置tabcontent和tabs的backgroundcolor来实现底部tabbar栏背景色突出的效果。

定义资源数据

由于“首页”和“我的”页面中有多处图片和文字的组合,因此提取出itemdata类。在mainviewmodel.ets文件中对页面使用的资源进行定义。

mainviewmodel代码

import { itemdata } from './itemdata';

export class mainviewmodel {
  private swiperimages: resource[] = [
  $r('app.media.fig1'),
  $r('app.media.fig2'),
  $r('app.media.fig3'),
  $r('app.media.fig4')
  ];
  private firstgriddata: itemdata[] = [
    new itemdata($r('app.string.my_love'), $r('app.media.love')),
    new itemdata($r('app.string.history_record'), $r('app.media.record')),
    new itemdata($r('app.string.message'), $r('app.media.message')),
    new itemdata($r('app.string.shopping_cart'), $r('app.media.shopping')),
    new itemdata($r('app.string.my_goal'), $r('app.media.target')),
    new itemdata($r('app.string.group'), $r('app.media.circle')),
    new itemdata($r('app.string.favorites'), $r('app.media.favorite')),
    new itemdata($r('app.string.recycle_bin'), $r('app.media.recycle'))
  ];
  private secondgriddata: itemdata[] = [
    new itemdata($r('app.string.mainpage_top'), $r('app.media.top'), $r('app.string.mainpage_text_top')),
    new itemdata($r('app.string.mainpage_new'), $r('app.media.new'), $r('app.string.mainpage_text_new')),
    new itemdata($r('app.string.mainpage_brand'), $r('app.media.brand'), $r('app.string.mainpage_text_brand')),
    new itemdata($r('app.string.mainpage_found'), $r('app.media.found'), $r('app.string.mainpage_text_found')),
  ];

  private settinglistdata: itemdata[] = [
    new itemdata($r('app.string.setting_list_news'), $r('app.media.news'), $r("app.string.setting_toggle")),
    new itemdata($r('app.string.setting_list_data'), $r('app.media.data')),
    new itemdata($r('app.string.setting_list_menu'), $r('app.media.menu')),
    new itemdata($r('app.string.setting_list_about'), $r('app.media.about')),
    new itemdata($r('app.string.setting_list_storage'), $r('app.media.storage')),
    new itemdata($r('app.string.setting_list_privacy'), $r('app.media.privacy'))
  ];

  getswiperimags(): array<resource> {
    return this.swiperimages
  }

  getgriddata(type: number): array<itemdata> {
    switch (type) {
      case 0:
        return this.firstgriddata
        break
      case 1:
        return this.secondgriddata
        break
      default:
        return this.firstgriddata
        break
    }
  }

  getsettinglistdata(): array<itemdata>{
    return this.settinglistdata
  }
}

export default new mainviewmodel()

itemdata代码

export class itemdata{
  /**
   * text of list item.
   */
  title: resource;
  /**
   * image of list item.
   */
  img: resource;
  /**
   * other resource of list item.
   */
  others?: resource;

  constructor(title: resource, img: resource, others?: resource) {
    this.title = title;
    this.img = img;
    this.others = others;
  }
}

实现“首页”内容

从效果图可以看出“首页”由三部分内容组成分别是轮播图、2*4栅格图、2*2栅格图。首先使用swiper组件实现轮播图,无需设置图片大小。

然后使用grid组件实现2*4栅格图。

使用grid组件实现2*2栅格列表栏,其中单个栅格中有一张背景图片和两行字体不同的文本,因此在column组件中放置两个text组件,并设置背景图,注意grid组件必须设置高度,否则可能出现页面空白。

mainpage代码

import router from '@ohos.router'
import commonconstants from '../common/constants/commonconstants'
import home from '../view/home'
import mime from '../view/mime'

@entry
@component
struct mainpage {
  @state fontcolor: string = '#182431'
  @state selectedfontcolor: string = '#007dff'
  @state currentindex: number = 0
  private controller: 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'))
        .objectfit(imagefit.contain)
      text(title)
        .fontcolor(this.currentindex === index ? $r('app.color.mainpage_selected') : $r('app.color.mainpage_normal'))
        .fontsize($r('app.float.main_tab_fontsize'))
    }
    .width('100%')
  }

  build() {
    column() {
      tabs({ barposition: barposition.end, controller: this.controller }) {
        tabcontent() {
          home()
        }.tabbar(this.tabbuilder(
          commonconstants.home_title,
          commonconstants.home_tab_index,
          $r('app.media.home_selected'),
          $r('app.media.home_normal')))

        tabcontent() {
          mime()
        }.tabbar(this.tabbuilder(
          commonconstants.mine_title,
          commonconstants.mine_tab_index,
          $r('app.media.mine_selected'),
          $r('app.media.mine_normal')))

      }
      .vertical(false)
      .width(commonconstants.full_parent)
      .backgroundcolor(color.white)
      .barheight($r('app.float.mainpage_barheight'))
      .barmode(barmode.fixed)
      .onchange((index: number) => {
        this.currentindex = index
       /* if(this.currentindex == 1){
          router.pushurl({
            url:'./pages/mime'
          })
        }*/
      })

    }
    .width(commonconstants.full_parent)
    .height(commonconstants.full_parent)
    .justifycontent(flexalign.end)

  }
}

home代码

import commonconstants from '../common/constants/commonconstants'
import { itemdata } from '../viewmodel/itemdata'
import mainviewmodel from '../viewmodel/mainviewmodel'

@component
export default struct home {
  private swipercontroller: swipercontroller = new swipercontroller()
  private gridscroller: scroller = new scroller()

  build() {
    column({ space: commonconstants.common_space }) {
      column() {
        text($r('app.string.mainpage_tabtitles_home'))
          .fontweight(fontweight.medium)
          .fontsize($r('app.float.page_title_text_size'))
          .margin({ top: $r('app.float.mainpage_tabtitles_margin') })
          .padding({ left: $r('app.float.mainpage_tabtitles_padding') })
      }
      .width(commonconstants.full_parent)
      .alignitems(horizontalalign.start)

      swiper(this.swipercontroller) {
        foreach(mainviewmodel.getswiperimags(), (img: resource) => {
          image(img).borderradius($r('app.float.home_swiper_borderradius'))
        }, (img: resource) => json.stringify(img.id))
      }
      .width(commonconstants.full_parent)
      .height($r('app.float.home_swiper_height'))
      .margin({ top: $r('app.float.home_swiper_margin') })
      .autoplay(true)

      grid() {
        foreach(mainviewmodel.getgriddata(0), (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'))
      .padding({ top: $r('app.float.home_grid_padding'), bottom: $r('app.float.home_grid_padding') })
      .height($r('app.float.home_grid_height'))
      .backgroundcolor(color.white)
      .borderradius($r('app.float.home_grid_borderradius'))

      text($r('app.string.home_list'))
        .fontsize($r('app.float.normal_text_size'))
        .fontweight(fontweight.medium)
        .width(commonconstants.common_width_90)
        .margin({ top: $r('app.float.home_text_margin') })

      grid(this.gridscroller) {
        foreach(mainviewmodel.getgriddata(1), (seconditem: itemdata) => {
          griditem() {
            column() {
              text(seconditem.title)
                .fontsize($r('app.float.normal_text_size'))
                .fontweight(fontweight.medium)
              text(seconditem.others)
                .margin({ top: $r('app.float.home_list_margin') })
                .fontsize($r('app.float.little_text_size'))
                .fontcolor($r('app.color.home_grid_fontcolor'))
            }
            .alignitems(horizontalalign.start)
          }
          .padding({ top: $r('app.float.home_list_padding'), left: $r('app.float.home_list_padding') })
          .borderradius($r('app.float.home_backgroundimage_borderradius'))
          .align(alignment.topstart)
          .backgroundimage(seconditem.img)
          .backgroundimagesize(imagesize.cover)
          .width(commonconstants.full_parent)
          .height(commonconstants.full_parent)


        }, (seconditem: itemdata) => json.stringify(seconditem))
      }
      .width(commonconstants.common_width_90)
      .height($r('app.float.home_secondgrid_height'))
      .columnstemplate('1fr 1fr')
      // .rowstemplate('1fr 1fr')
      .columnsgap($r('app.float.home_grid_columnsgap'))
      .rowsgap($r('app.float.home_grid_rowgap'))
      .layoutweight(1)
      .onscrollindex((first: number) => {
        console.info('111111111',first.tostring())
      })


    }
    .height(commonconstants.full_parent)
  }
}

实现“我的”页面内容

使用list组件结合foreach语句来实现页面列表内容。

mime代码

import commonconstants from '../common/constants/commonconstants'
import { itemdata } from '../viewmodel/itemdata'
import mainviewmodel from '../viewmodel/mainviewmodel'

@component
export default struct mime {
  @builder settingcell(item: itemdata) {
    column() {

      row() {
        row({ space: commonconstants.common_space_10 }) {
          image(item.img)
            .width($r('app.float.setting_size'))
            .height($r('app.float.setting_size'))
          text(item.title)
            .fontsize($r('app.float.normal_text_size'))
        }

        if (item.others === null || item.others === undefined) {
          image($r('app.media.right_grey'))
            .width($r('app.float.setting_jump_width'))
            .height($r('app.float.setting_jump_height'))
        } else {
          toggle({ type: toggletype.switch, ison: false })
        }

      }
      .justifycontent(flexalign.spacebetween)
      .width(commonconstants.full_parent)

    }

  }

  build() {

    column({ space: commonconstants.common_space_10 }) {
      text('我的')
        .width(commonconstants.common_width_90)
        .height(50)
        .fontsize(24)
        .fontweight(600)

      row() {
        image($r('app.media.account'))
          .width(50)
          .height(50)

        column() {
          text($r('app.string.setting_account_name'))
            .fontsize($r('app.float.setting_account_fontsize'))
            .fontweight(400)
          text($r('app.string.setting_account_email'))
            .fontsize($r('app.float.little_text_size'))
            .margin({ top: $r('app.float.setting_name_margin') })
        }
        .alignitems(horizontalalign.start)
        .margin({ left: $r('app.float.setting_padding') })
      }
      .margin({ top: $r('app.float.login_progress_margin_top') })
      .width(commonconstants.common_width_80)
      .justifycontent(flexalign.start)

      list() {
        foreach(mainviewmodel.getsettinglistdata(), (item: itemdata) => {
          listitem() {
            this.settingcell(item)
          }.height($r('app.float.setting_list_height'))

        }, (item: itemdata) => json.stringify(item))
      }
      .backgroundcolor(color.white)
      .width(commonconstants.common_width_90)
      .height(commonconstants.common_width_50)
      .margin({ top: $r('app.float.other_login_margin_top') })
      .borderradius($r('app.float.setting_list_borderradius'))
      .padding({ top: $r('app.float.setting_list_padding'), bottom: $r('app.float.setting_list_padding') })

      blank()
      button($r('app.string.setting_button'), { type: buttontype.capsule })
        .width(commonconstants.button_width)
        .height($r('app.float.login_button_height'))
        .fontsize($r('app.float.normal_text_size'))
        .fontcolor($r('app.color.setting_button_fontcolor'))
        .fontweight(fontweight.medium)
        .backgroundcolor($r('app.color.setting_button_backgroundcolor'))
        .margin({ bottom: $r('app.float.setting_button_bottom') })


    }
    .width(commonconstants.full_parent)
    .height(commonconstants.full_parent)

  }
}

总结

知识点:

  1. button、image、textinput、text等基础组件的使用。
  2. column、row、grid、list、tabs等容器组件的使用。
(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com