【HarmonyOS】体验鸿蒙电商平台的未来之旅!

           从今天开始,博主将开设一门新的专栏用来讲解市面上比较热门的技术 “鸿蒙开发”,对于刚接触这项技术的小伙伴在学习鸿蒙开发之前,有必要先了解一下鸿蒙,从你的角度来讲,你认为什么是鸿蒙呢?它出现的意义又是什么?鸿蒙仅仅是一个手机操作系统吗?它的出现能够和Android和IOS三分天下吗?它未来的潜力能否制霸整个手机市场呢?

今天实现一个简单的小案例,从零开始讲解如何通过鸿蒙开发实现一个电商平台的案例。

目录

新建项目

登录页面

点击登录

个人中心

首页搭建

Tabs组件


新建项目

首先我们先打开DevEco Studio,点击新建项目:

然后根据自己的情况选择应用,这里我们选择空的 Empty Ability 进行创建:

然后接下来输入自己的项目名称就行,点击finish即可:

运行本地预览器,可以看到我们的初始项目已经跑通:

登录页面

登录页面的构建很简单,我们参考网上的登录页面,简单的构建一下登录页面的画面,这里我使用的图标都是来自阿里云图标库当中,大家可以根据自己的情况在网上寻找资源来构建画面,闲话少说我们直接开始,首先我们在pages文件夹下新建arkts文件Login文件,当作是我们的登录页面,接下来我们开始正式编写相关代码:

因为构建静态页面很简单,也没有什么好讲的,这里我就将静态页面的源代码直接共享出来吧,大家可以自己看一下:

// 登录页面

// 文本框样式
@Extend(TextInput) function InputStyle() {
  .placeholderColor('#ff5d7e9d')
  .height(60)
  .fontSize(20)
  .backgroundColor('#ccc')
  .width('90%')
  .padding({ left: 15 })
  .maxLength(10)
}

// 分割线
@Extend(Line) function liseStyle() {
  .width('100%')
  .height(2)
  .backgroundColor('#efefef')
  .margin({ top: 10, bottom: 10 })
}

// Text组件的蓝色文本样式
@Extend(Text) function blueTextStyle() {
  .fontColor('#ff084d85')
  .fontSize(15)
  .fontWeight(FontWeight.Bold)
}

@Entry
@Component
struct Login {
  @State account: string = '' // 登录账号
  @State password: string = '' // 登录密码
  @State isShowProgress: boolean = true // 是否显示登录的进度条
  // 构建登录按钮
  @Builder imageButton(image: Resource) {
    // 构建按钮图片,本质上就是在按钮里面增加一个image组件
    Button({ type: ButtonType.Circle, stateEffect: true }){ // 圆形按钮,按下按钮有切换颜色效果
      Image(image)
    }
    .height(50).width(50).backgroundColor('#fff')
  }

  build() {
    Column() { // 登录界面的布局
      Image($r('app.media.login_logo')) // 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_page'))
        .fontSize($r('app.float.page_title_text_size'))
        .fontWeight(FontWeight.Medium)
        .fontColor($r('app.color.page_title_text_color'))

      // 小标题
      Text('登录账号以获取更多服务')
        .fontSize(20)
        .fontColor('#ccc')
        .margin({ top: 15, bottom: 25 })

      // 账号输入框
      TextInput({ placeholder: '请输入账号' })
        .InputStyle()
        .type(InputType.Number) // 文本行中只能输入数字
        .onChange((value: string) => {
          this.account = value
        })
      Line()
        .liseStyle()
      // 密码输入框
      TextInput({ placeholder: '请输入密码' })
        .InputStyle()
        .type(InputType.Password)
        .onChange((value: string) => {
          this.password = value
        })
      Line()
        .liseStyle()

      // 短信提示与验证码
      Row(){
        Text('短信验证码登录').blueTextStyle()
        Text('忘记密码').blueTextStyle()
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)
      .padding({ left: 12, right: 12 })

      // 登录按钮
      Button('登录', { type: ButtonType.Capsule })
        .width('75%')
        .height(45)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 60, bottom: 20 })
        .onClick(() => {
          // 登录事件
        })

      // 注册账号文本
      Text('注册账号')
        .fontColor('blue').fontSize(15).fontWeight(FontWeight.Medium)

      // 是否显示进度条
      if (this.isShowProgress){
        LoadingProgress()
          .color('red').width(40).height(40).margin({ top: 10 })
      }

      // 其他方式登录
      Text('其他方式登录').fontColor('#ff776f6f').fontSize(18)
        .fontWeight(FontWeight.Medium).margin({ top: 5, bottom: 10 })

      // 三种登录方式
      Row({ space: 40 }){
        this.imageButton($r("app.media.wx"))
        this.imageButton($r("app.media.tb"))
        this.imageButton($r('app.media.qq'))
      }
    }
    .width('100%')
    .height('100%')
  }
}

最终呈现的效果如下:

关于这个静态页面的构建我简单提一下,对于公共常用的样式,我们可以将其书写在静态资源base当中然后进行调用即可,上文的代码我进行了简单的使用,主要的方式如下:

点击登录

接下来我们给我们静态页面的登录按钮设置点击事件进行登录操作,以及对进度条的显示进行一个设置,当点击登录和进入到正式页面之间的间隔中进行显示这个进度条出来,闲话少说正式开始:

@State isShowProgress: boolean = false // 是否显示登录的进度条
private timeOutId: number = -1 // 控制登录超时的时间变量

// 登录回调事件
Login(): void {
  if(this.account === '' || this.password === ''){
    promptAction.showToast({ // 开启一个确认弹层
      message: '账号密码为空,请重新输入!'
    })
  } else {
    this.isShowProgress = true
    if(this.timeOutId == -1) {
      this.timeOutId = setTimeout(() => {
        // 2秒之后执行的函数
        this.isShowProgress = false
        this.timeOutId = -1
        // 页面跳转
      }, 2000)
    }
  }
}

然后我们在离开页面的时候,对定时器进行一个清除:

// 离开页面要取消定时器
aboutToDisappear() {
  clearTimeout(this.timeOutId)
  this.timeOutId = -1
}

实现的效果如下:

接下来我们开始实现点击登录按钮后,触发点击事件进行页面的路由跳转,代码如下,关于个人中心页面的搭建,可以继续看下一个标题的内容:

个人中心

接下来开始实现个人中心的页面,个人中心的页面搭建其实也非常简单,这里我们把要存放的图片和相关标题的内容单独抽离出去,形成一个新的类,来获取静态资源,后面需求页面要使用的时候直接调用就可以了,具体代码如下:

interface ItemData {
  title: string;
  imagePath: Resource;
  switch?: boolean;
}

export class DataModel {
  // 获取列表数据
  getSettingListData(): ItemData[] {
    let settingListData: ItemData[] = [
      {
        title: '推送通知',
        imagePath: $r('app.media.1'),
        switch: true,
      },
      {
        title: '数据管理',
        imagePath: $r('app.media.2'),
        switch: false,
      },
      {
        title: '菜单设置',
        imagePath: $r('app.media.3'),
        switch: false,
      },
      {
        title: '关于个人',
        imagePath: $r('app.media.4'),
        switch: false,
      },
      {
        title: '清除缓存',
        imagePath: $r('app.media.5'),
        switch: false,
      },
      {
        title: '隐私协议',
        imagePath: $r('app.media.6'),
        switch: false,
      },
    ];
    return settingListData;
  }
}

export default new DataModel();

关于这些静态资源的图片可以到阿里云图标库上寻找,这里就不再赘述了:

然后接下来我们需要开始正式的书写我们的个人中心页面的代码了,具体静态页面代码如下:

import router from '@ohos.router'
import DataModel from '../../components/DataModel'
import promptAction from '@ohos.promptAction'

// 设置界面
@Entry
@Component
struct MySettings {
  @State account: number = 0

  onPageShow(){
    let acc = router.getParams() as Record<string, number>
    if (acc) {
      this.account = acc['sendMsg']
    }
  }

  // 构建设置单元格函数
  @Builder settingCell(item) {
    Row(){
      Row({ space: 10 }) {
        Image(item.imagePath).width(38).height(38)
        Text(item.title).fontSize(25)
      }
      // 判断switch是否为true
      if(!item.switch) {
        Image($r('app.media.arrow_right')).width(30).height(30)
      } else {
        Toggle({ type: ToggleType.Switch, isOn: false }) // 显示一个开关组件
      }
    }
    .justifyContent(FlexAlign.SpaceBetween)
    .width('100%')
    .padding({ left: 15, right: 15 })
  }

  build() {
    Scroll(){
      Column({ space: 12 }){
        Column(){ // 创建一个内嵌的列布局
          Text('个人中心').fontWeight(FontWeight.Bold).fontSize(40)
            .margin({ top: 10 }).padding({ left: 15 })
        }
        .width('100%')
        .alignItems(HorizontalAlign.Start)

        // 账户布局
        Row(){
          Image($r('app.media.account')).width(60).height(60)
          Column(){
            Text('张三').fontSize(25)
            Text(`${this.account.toString()}@163.com`).fontSize(15).margin({ top: 8 })
          }
          .layoutWeight(2)
          .alignItems(HorizontalAlign.Start)
          .margin({ left: 30 })
        }
        .width('100%')
        .height(70)
        .backgroundColor(Color.White)
        .padding({ left: 20, right: 20 })
        .borderRadius(20)
        .margin({ top: 30 }).alignItems(VerticalAlign.Center)

        // 列表布局
        List(){
          ForEach(DataModel.getSettingListData(), (item, index) => {
            ListItem(){
              this.settingCell(item)
            }
            .onClick(() => {
              promptAction.showDialog({
                message: `第${index + 1}功能:${item.title},还未完成,尽情期待!`
              })
            })
            .height(60)
          })
        }
        .backgroundColor(Color.White)
        .width('100%')
        .divider({
          strokeWidth: 1, // 设置分割线的高度
          color: Color.Gray, // 设置分割线的颜色
          startMargin: 15, // 设分割线的起始边距
          endMargin: 15 // 设置分割线的结束边距
        })
        .borderRadius(30)
        .padding({ top: 15, bottom: 20 })

        Blank()

        // 退出按钮的布局
        Button('退出登录', { type: ButtonType.Capsule })
          .width('90%').height(50).fontSize(20).fontColor('red')
          .backgroundColor('#ccc').margin({ bottom: 15 })
      }
      .height('100%')
    }
    .width('100%')
    .height('100%')
  }
}

呈现的效果如下所示:

然后接下来我们给退出登录的按钮设置点击事件:

首页搭建

接下来开始实现首页的页面搭建,静态页面的搭建其实很简单,博主也没有什么好讲的说实话,无非就是Grid布局以及Swiper布局的排版一下注意一点就可以了,ok接下来我们开始给出具体代码吧:

import DataModel from '../../components/DataModel'

// 首页
@Entry
@Component
struct Home {
  private swiperController: SwiperController = new SwiperController() // 轮播控制器实例

  build() {
    Scroll(){
      Column({ space: 10 }){
        Column(){ // 标题
          Text('首页').fontWeight(FontWeight.Bold).fontSize(30)
            .margin({ top: 10 }).padding({ left: 10 })
        }
        .width('100%').alignItems(HorizontalAlign.Start)

        // 轮播图片
        Swiper(this.swiperController){
          ForEach(DataModel.getSwiperImage(), (item) => {
            // 构建每一张图片
            Image(item.imagePath)
              .width('100%')
              .height(250)
              .borderRadius(50)
          })
        }
        .autoPlay(true) // 轮播图自动播放
        .margin({ top: 15 })

        // 菜单列表
        Grid(){
          ForEach(DataModel.getFirstGridData(), (item) => {
            GridItem(){
              Column(){
                Image(item.imagePath).width(40).height(40)
                Text(item.title).fontSize(15).margin({ top: 5 })
              }
            }
          })
        }
        .columnsTemplate('1fr 1fr 1fr 1fr') // 设置网格的列模板,每列平分空间
        .rowsTemplate('1fr 1fr') // 设置网格的行模板,每行平分空间
        .columnsGap(10)
        .rowsGap(10)
        .padding({ top: 10, bottom: 10 })
        .height(200)
        .backgroundColor(Color.White)
        .borderRadius(50)

        // 频道列表
        Text('列表').fontSize(20).fontWeight(FontWeight.Bold).width('100%')
          .margin({ top: 15 })
        Grid(){
          ForEach(DataModel.getSecondGridData(), (item) => {
            GridItem() {
              Column() {
                Text(item.title).fontSize(20).fontWeight(FontWeight.Medium)
                Text(item.describe).fontSize(15).fontColor('#ccc').margin({ top: 5 })
              }
              .alignItems(HorizontalAlign.Start) // 两个文本框在水平方向居左对齐
            }
            .padding({ top: 15, left: 10 }).borderRadius(10)
            .align(Alignment.TopStart) // 设置网格项对齐方式为顶部对齐
            .backgroundImage(item.imagePath) // 设置网格项背景图像
            .backgroundImageSize(ImageSize.Cover) // 设置背景图像尺寸模式为覆盖
            .width('100%').height('100%')
          })
        }
        .width('100%').height(300)
        .columnsTemplate('1fr 1fr').rowsTemplate('1fr 1fr') // 设置网格的行列模板
        .columnsGap(10).rowsGap(10).margin({ bottom: 15 })
      }
    }
    .height('100%')
  }
}

最终呈现的效果如下:

Tabs组件

ArkUI开发框架提供了一种页签容器标签Tabs,开发者通过Tabs组件可以很容易的实现内容视图的切换。页签容器 Tabs 的形式多种多样,不同的页面设计页签不一样,可以把页签设置在底部、顶部或者侧边。

接下来我们创建页面组件index,然后在页面组件当中书写tab页面:

import Home from './Home'
import MySettings from './MySettings'
import router from '@ohos.router'

// app主页,页面组件
@Entry
@Component
struct Index {
  @State currentIndex: number = 0 // 当前默认的页签索引号
  private account: number
  private tabsController: TabsController = new TabsController()

  // 接收路由参数
  onPageShow(){
    let acc = router.getParams() as Record<string, number>
    if (acc) {
      this.account = acc['sendMsg']
    }
  }

  // 自定义Tabs函数
  @Builder TabBuilder(title: string, index: number, selectedImg: Resource, normalImg: Resource) {
    Column() {
      Image(this.currentIndex == index ? selectedImg : normalImg)
        .width(30).height(30)
      Text(title).margin({ top: 5 }).fontSize(15)
        .fontColor(this.currentIndex == index ? '#008c8c' : '#ccc')
    }
    .justifyContent(FlexAlign.Center)
    .width('100%').height('50')
    .onClick(() => {
      this.currentIndex = index
      this.tabsController.changeIndex(this.currentIndex) // 修改页签的索引
    })
  }
  build() {
    Tabs({
      barPosition: BarPosition.End, // 页签底部展示
      controller: this.tabsController // 页签容器的控制
    }){ // 标签容器
      // 首页
      TabContent(){
        Home()
      }
      .padding({ left: 20, right: 20 }).backgroundColor('#ccc')
      .tabBar(this.TabBuilder('首页', 0, $r('app.media.home_active'), $r('app.media.home')))
      // 个人中心
      TabContent(){
        MySettings({ account: this.account })
      }
      .padding({ left: 20, right: 20 }).backgroundColor('#ccc')
      .tabBar(this.TabBuilder('我的', 1, $r('app.media.my_active'), $r('app.media.my')))
    }
    .animationDuration(0) // 去掉切换页面的动画效果
    .scrollable(false) // 去掉滑动效果,只能点击按钮切换界面
    .width('100%')
    .backgroundColor(Color.White)
    .barHeight(50)
    .barMode(BarMode.Fixed)
  }
}

这里我们需要将之前的Home页面以及MySettings页面进行一个暴露出去:

这里简单提一下,当用户点击登录按钮之后,这里我们需要跳转到index页面的,所以携带的路由参数也是先传递给index页面,然后index页面再传递给子组件MySettings组件当中,这里注意一下:

最终呈现的效果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/339898.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OceanBase在作业帮业务的应用实践

作业帮成立于 2015 年&#xff0c;致力于用科技手段助力教育普惠&#xff0c;运用人工智能、大数据等技术&#xff0c;为学生、老师、家长提供学习、教育解决方案&#xff0c;智能硬件产品等。 在业务初期&#xff0c;作业帮使用阿里云 ECS 自建 MySQL&#xff0c;同时最大程度…

揭开Spring MVC的真面目

官方对于Spring MVC的描述为&#xff1a; Spring Web MVC是基于Servlet API框架构建的原始Web框架&#xff0c;从一开始就包含在Spring框架中。它的正式名称“Spring Web MVC”来自其源模块的名称&#xff08;Spring-webmvc&#xff09;&#xff0c;但它通常被称为“Spring-MVC…

网络通信(Socket/TCP/UDP)

一、Socket 1.概念: Socket(又叫套接字)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接协议,客户端的IP地址,客户端的端口,服务器的IP地址,服务器的端口。 一个Socket是一对IP地址…

OpenGPTs:一款外挂般的GPTs管理器,由ChatPaper团队开源!

OpenGPTs-非常好用的开源GPTs管理器. 一句话介绍 非常好用的GPTs管理器&#xff0c;ChatPaper团队开源一款功能强大的浏览器插件&#xff0c;适合所有拥有Plus权限的朋友。 为什么要做OpenGPTs&#xff1f; &#x1f914;&#x1f4a1; 众所周知&#xff0c;OpenAI官网的GPT…

飞书+ChatGPT+cpolar搭建企业智能AI助手并实现无公网ip远程访问

文章目录 推荐 前言环境列表1.飞书设置2.克隆feishu-chatgpt项目3.配置config.yaml文件4.运行feishu-chatgpt项目5.安装cpolar内网穿透6.固定公网地址7.机器人权限配置8.创建版本9.创建测试企业10. 机器人测试 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂…

Vue2中CesiumV1.113.0加载离线地图

Vue2中CesiumV1.113.0加载离线地图&#xff0c;本文以天地图为例。 1.使用nodejs获取天地图 新建nodejsdownmap项目文件夹&#xff0c;初始化项目 npm init -y src/index.js // An highlighted block var Bagpipe require(bagpipe) var fs require("fs"); var r…

项目解决方案:某城区(区县)社会面视频监控资源接入汇聚解决方案

目 录 一、概述 二、建设目标及需求 1.建设目标 2.需求分析 2.1 总体需求 2.2 需求细化 三、方案设计 1.设计依据 2.设计原则 3.设计方案 3.1.方案描述 3.2.组网说明 四、产品介绍 1.视频监控综合资源管理平台介绍 2.视频录像服务器和存储 2.1…

基于SpringBoot的SSM整合案例

项目目录: 数据库表以及表结构 user表结构 user_info表结构 引入依赖 父模块依赖: <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.12.RELEASE</version>…

自动弹性,QPS线性提升|一文读懂云原生数仓AnalyticDB弹性技术原理

前言 在全球经济增长放缓的大背景之下&#xff0c;企业在加强数字化建设的过程中&#xff0c;实现效益最大化成为一个绕不开的话题。阿里云瑶池旗下的云原生数仓AnalyticDB MySQL湖仓版&#xff08;以下简称AnalyticDB MySQL&#xff09;在发布之初提供了定时弹性功能&#xf…

本地读取Excel文件并进行数据压缩传递到服务器

在项目开发过程中&#xff0c;读取excel文件&#xff0c;可能存在几百或几百万条数据内容&#xff0c;那么对于大型文件来说&#xff0c;我们应该如何思考对于大型文件的读取操作以及性能的注意事项。 类库&#xff1a;Papa Parse - Powerful CSV Parser for JavaScript 第一步…

漏洞复现-SpringBlade export-user SQL 注入漏洞(附漏洞检测脚本)

免责声明 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的…

什么是ORM?

ORM&#xff08;Object-Relational Mapping&#xff0c;对象关系映射&#xff09;是一种编程技术&#xff0c;它的目标是实现面向对象编程语言与关系型数据库之间的数据映射和转换。ORM系统允许开发人员使用面向对象的方式来操作数据库&#xff0c;而无需直接编写复杂的SQL查询…

Cesium叠加超图二维服务、三维场景模型

前言 Cesium作为开源的库要加超图的服务则需要适配层去桥接超图与Cesium的数据格式。这个工作iClient系列已经做好&#xff0c;相比用过超图二维的道友们可以理解&#xff1a;要用Openlayer加载超图二维&#xff0c;那就用iClient for Openlayer库去加载&#xff1b;同样的要用…

mac自带录屏

1、打开 快捷键&#xff1a;Shift Command5 可以在指定存储位置 2、结束 快捷键&#xff1a; CommandControlEsc&#xff08;也可以点击顶部工具栏的结束按钮&#xff09;

图像数据增广

目录 一、常用的图像增广方法 1、随机翻转 2、随机裁剪 3、随机颜色变换 二、图像代码实现 1、定义图像显示辅助函数 2、随机翻转 3、随机裁剪 4、随机颜色变换 5、结合多种图像增广方法 三、使用图像增广进行训练 1、下载数据集 2、读取图像并增广 3、多GPU训练 …

麦芯(MachCore)应用开发教程2 --- 时序

黄国强 2024/01/22 正如计算机的本质是状态机一样&#xff0c;设备也是一个状态机。笔者之前文章“什么是时序”用 switch/case 实现了状态机。在麦芯中&#xff0c;我们用Lambda实现了状态机。相对于switch/case&#xff0c;Lambda更优雅&#xff0c;更符合面向对象。先上代码…

单元化(Set)架构设计详解:异地多活、突破扩展上限的优选方案

文章目录 一、单元化架构基础1、扩展性&#xff08;Scalability&#xff09;概述2、扩展性 - 横向扩展&#xff08;Horizontal Scale&#xff09;3、扩展性 - 纵向扩展&#xff08;Vertical Scale&#xff09;4、扩展性 - 扩展魔方5、一致性 - 数据库事务一致性&#xff08;ACI…

【中文版ChatGPT4.0!国内可直接用】

中文版ChatGPT4.0&#xff01;国内可直接用 文心一言微软Copilot迅捷AI写作 在国内使用ChatGPT 4.0可能需要支付每月20美元的费用&#xff0c;约合人民币145元。如果不愿意付费&#xff0c;也可以考虑使用其他免费的AI工具。 目前有许多公司在研发出色的AI大模型&#xff0c;这…

Python进阶-Anaconda使用总结

本文是 Anaconda 的使用总结&#xff0c;旨在帮助用户快速搭建 Python 环境、进行数据科学和机器学习工作。首先&#xff0c;介绍了在 Windows 系统上安装 Anaconda 的步骤&#xff0c;包括下载安装程序、配置环境变量以及验证安装。随后&#xff0c;详细列举了 Anaconda 的常用…

新版AndroidStudio dependencyResolutionManagement出错

在新版AndroidStudio中想像使用4.2版本或者4.3版本的AndroidStudio来构造项目&#xff1f;那下面这些坑我们就需要来避免了&#xff0c;否则会出各种各样的问题。 一.我们先来看看新旧两个版本的不同。 1.jdk版本的不同 新版默认是jdk17 旧版默认是jdk8 所以在新版AndroidSt…