HarmonyOS应用开发ArkUI(TS)电商项目实战

项目介绍

本项目基于 HarmonyOS 的ArkUI框架TS扩展的声明式开发范式,关于语法和概念直接看官网官方文档地址:基于TS扩展的声明式开发范式,

工具版本: DevEco Studio 3.1 Canary1

SDK版本: 3.1.9.7(API Version 8 Release)

效果演示

页面解析

主框架

使用容器组件:Tabs 、TabContent、作为主框架,底部Tab使用自定义布局样式,设置点击事件,每次点击更换选中的索引。来切换内容页面。

使用自定义组件来实现:首页、分类、购物车、我的的搭建。

@Entry
@Component
struct MainFrame {
  @State selectIndex: number = 0
  private controller: TabsController = new TabsController()
  private tabBar = getTabBarList()

  // 内容
  @Builder Content() {
    Tabs({ controller: this.controller }) {
      TabContent() {HomeComponent()}
      TabContent() {ClassifyComponent()}
      TabContent() {ShoppingCartComponent({ isShowLeft: false })}
      TabContent() {MyComponent()}
    }
    .width('100%')
    .height(0)
    .animationDuration(0)
    .layoutWeight(1)
    .scrollable(false)
    .barWidth(0)
    .barHeight(0)
  }

  // 底部导航
  @Builder TabBar() {
    Row() {
      ForEach(this.tabBar, (item: TabBarModel, index) => {
        Column() {
          Image(this.selectIndex === index ? item.iconSelected : item.icon)
            .width(23).height(23).margin({ right: index === 2 ? 3 : 0 })
          Text(item.name)
            .fontColor(this.selectIndex === index ? '#dc1c22' : '#000000')
            .margin({ left: 1, top: 2 })
        }.layoutWeight(1)
        .onClick(() => {
          this.selectIndex = index
          this.controller.changeIndex(index)
        })
      }, item => item.name)
    }.width('100%').height(50)
    .shadow({ radius: 1, color: '#e3e2e2', offsetY: -1 })
  }

  build() {
    Column() {
      this.Content()
      this.TabBar()
    }.width('100%').height('100%')
  }
}
首页

因为顶部标题栏需要浮在内容之上,所以根布局使用 容器组件Stack ,内容布局最外层使用 容器组件Scroll 来实现滑动,内容整体分为3部分:

  1. 轮播图:使用 容器组件Swiper
  2. 菜单:使用 容器组件Flex 、默认横向布局,子布局宽度分为五等分,设置Flex的参数:wrap: FlexWrap.Wrap可实现自动换行。
  3. 商品列表:和菜单的实现方式一样,只不过宽度是二等分

向下滑动时标题栏显示功能:使用 容器组件Scroll 的属性方法:onScroll来判断y轴方向的偏移量,根据偏移量计算出比例,改变标题栏的透明度。

(以下是部分代码)


@Component
export struct HomeComponent {
  // 滑动的y偏移量
  private yTotalOffset = 0
  // 标题栏透明度
  @State titleBarOpacity: number = 0
  // 轮播图列表
  private banners = [
    $r("app.media.banner1"), $r("app.media.banner2"), $r("app.media.banner3"),
    $r("app.media.banner4"), $r("app.media.banner5"), $r("app.media.banner6"),
  ]
  // 菜单列表
  private menuList = getHomeMenuList()
  // 商品列表
  private goodsList: Array<HomeGoodsModel> = getHomeGoodsList()


  // 轮播图
  @Builder Banner() {...}

  // 菜单
  @Builder Menu() {....}

  // 商品列表
  @Builder GoodsList() {...}

  build() {
    Stack({ alignContent: Alignment.Top }) {
      Scroll() {
        Column() {
          this.Banner()
          this.Menu()
          this.GoodsList()
        }.backgroundColor(Color.White)
      }.scrollBar(BarState.Off)
      .onScroll((xOffset, yOffset) => {
        this.yTotalOffset += yOffset
        const yTotalOffsetVP = px2vp(this.yTotalOffset)
        // 轮播图高度 350
        const scale = yTotalOffsetVP / 200
        this.titleBarOpacity = scale
      })

      Row(){
        TitleBar({
          title: '首页',
          isShowLeft: false,
          isShowRight: true,
          rightImage: $r('app.media.search')
        })
      }.opacity(this.titleBarOpacity)
    }.width('100%').height('100%')
  }
}
详情页

和首页类似,根布局使用容器组件Stack,内容布局最外层使用容器组件Scroll 来实现滑动。因为详情页有相同布局,使用装饰器@Builder来抽离公共布局。

向下滑动时标题栏显示功能原理和首页一样

(以下是部分代码)

import router from '@ohos.router';

@Entry
@Component
struct GoodsDetail {
  ....
  // 轮播图
  @Builder Banner() {...}

  // 内容item
  @Builder ContentItem(title: string, content: string, top=1) {
    Row() {
      Text(title).fontSize(13).fontColor('#808080')
      Text(content).fontSize(13).margin({ left: 10 }).fontColor('#ff323232')
      Blank()
      Image($r('app.media.arrow')).width(12).height(18)
    }.width('100%').padding(13)
    .backgroundColor(Color.White).margin({ top: top })
  }
  // 内容
  @Builder Content() {
    ...
    this.ContentItem('邮费', '满80包邮', 7)
    this.ContentItem('优惠', '减5元')
    this.ContentItem('规格', '山核桃坚果曲奇; x3', 7)
    this.ContentItem('配送', '北京市朝阳区大塔路33号')
  }

  // 评论
  @Builder Comment() {...}

  // 商品参数item
  @Builder GoodsParamItem(title: string, content: string) {
    Row() {
      Text(title).width(100).fontSize(13).fontColor('#808080')
      Text(content).fontSize(13).fontColor('#ff323232')
        .layoutWeight(1).padding({ right: 20 })
    }.width('100%').padding({ top: 15 })
    .alignItems(VerticalAlign.Top)
  }
  // 商品参数
  @Builder GoodsParam() {...}

  build() {
    Stack() {
      Scroll() {
        Column() {
          this.Banner()
          this.Content()
          this.Comment()
          this.GoodsParam()
        }
      }.scrollBar(BarState.Off)
      .onScroll((xOffset, yOffset) => {
        this.yTotalOffset += yOffset
        const yTotalOffsetVP = px2vp(this.yTotalOffset)
        // 轮播图高度 350
        const scale = yTotalOffsetVP / 350
        this.titleBarBgTmOpacity = 1 - scale
        if (scale > 0.4) {
          this.titleBarBgWhiteOpacity = scale - 0.2
        } else {
          this.titleBarBgWhiteOpacity = 0
        }
      })

      this.TopBottomOperateBar()
    }.width('100%').height('100%')
    .backgroundColor('#F4F4F4')
  }
}
分类

此页面很简单,就是左右两个容器组件List、一个宽度30%,一个宽度70%,使用循环渲染组件ForEach来渲染列表。

(以下是部分代码)

@Component
export struct ClassifyComponent {
  // 搜索
  @Builder Search() {...}

  // 内容
  @Builder Content() {
    Row() {
      // 左分类
      List() {...}.width('30%')

      // 右分类
      List({scroller:this.scroller}) {...}.width('70%')

    }.width('100%').layoutWeight(1)
    .alignItems(VerticalAlign.Top)
  }

  build() {
    Column() {
      this.Search()
      this.Content()
    }.width('100%').height('100%')
    .backgroundColor(Color.White)
  }
}
购物车

此界面功能:全选、单选、删除商品、更改商品的数量。当有商品选中,右上角删除按钮显示。更改商品数量同步更新合计的总价格。

使用List组件来实现列表。数据数组使用装饰器@State定义。数据更新必须是更改数组的项

(以下是部分代码)

@Component
export struct ShoppingCartComponent {
  ...
  // 商品详情
  @Builder GoodsItem(item: ShoppingCartModel, index: number) {...}

  build() {
    Column() {
      TitleBar()
        
      if (this.list.length > 0) {
        // 列表  
        List() {...}.layoutWeight(1)
        // 结算布局
        Row() {...}
      } else {
        Row() {
          Text('空空如也~')
        }
      }
    }.width('100%').height('100%')
    .backgroundColor('#F4F4F4')
  }

  selectOperation(item: ShoppingCartModel, index: number) {
    // 替换元素,才能更改数组,这样页面才能更新
    let newItem = {...item}
    newItem.isSelected = !item.isSelected
    this.list.splice(index, 1, newItem)

    this.calculateTotalPrice()
  }

  // 加/减操作
  addOrSubtractOperation(item: ShoppingCartModel, index: number, type: -1 | 1) {...}

  // 计算合计
  calculateTotalPrice() {
    let total = 0
    let selectedCount = 0
    for (const item of this.list) {
      if (item.isSelected) {
        selectedCount++
        total += item.newPrice * item.count
      }
    }
    this.totalPrice = total
    this.isAllSelected = selectedCount === this.list.length
  }
}

结尾

此项目没有比较难的点,都是照着官方文档,查阅API做出来的,依靠着声明式UI的简洁和强大,页面搭建效率很高。

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

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

相关文章

海外媒体软文发稿:带动海外宣发新潮流,迈向国际舞台

引言 随着全球化的发展&#xff0c;越来越多的中国企业希望在国际舞台上展示自己的实力。而海外媒体软文发稿作为一种全新的海外宣传方式&#xff0c;正逐渐成为带动海外宣发新潮流的有力工具。本文将探讨海外媒体软文发稿的优势和如何迈向国际舞台。 海外媒体软文发稿的优势…

代码随想录阅读笔记-二叉树【最大二叉树】

题目 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下&#xff1a; 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出的最大二叉树。右子树是通过数组中最大值右边部分构造出的最大二叉树。 通过给定的数组构建最大二叉树&#x…

linux系统负载对系统的意义

负载平均值的含义 负载平均值是通过uptime和top命令显示的三个数字&#xff0c;分别代表不同时间段的平均负载&#xff08;1分钟、5分钟和15分钟的平均值&#xff09;。这三个数字越低越好&#xff0c;较高的数字意味着系统可能存在问题或过载。然而&#xff0c;并没有一个固定…

男生穿什么裤子最帅?必备的男生裤子推荐

每个人都想拥有很多条好看质量又好的裤子。不过市面上有太多服装品牌&#xff0c;甚至还有不少劣质的衣裤&#xff0c;穿洗两遍之后就出现松垮、变形的情况。为了能够让大家可以选到合适的衣裤&#xff0c;我自费购买了多个品牌的裤子&#xff0c;并给出大家测评结果。 购买到质…

网站访问502,网站服务器崩溃,比较常见几个的原因

其实&#xff0c;配置再好的服务器也难免在使用过程中出现一些故障&#xff0c;造成宕机。 服务器一旦出现故障&#xff0c;影响到用户实时访问网站&#xff0c;造成用户流失&#xff0c;如果在企业的销售高峰期&#xff0c;则将直接影响到商业利润&#xff0c;而且不仅影响外…

SD-WAN降低网络运维难度的三大关键技术

企业网络作为现代企业不可或缺的基础设施&#xff0c;承担着连接全球的重要任务。随着全球化和数字化转型的加速推进&#xff0c;企业面临着越来越多的网络挑战和压力。传统的网络组网方式已经不能满足企业规模扩大、分支机构增多、上云服务等需求&#xff0c;导致了网络性能下…

消除歧义:利用动态上下文提出有效的RAG问题建议

原文地址&#xff1a;disambiguation-using-dynamic-context-in-crafting-effective-rag-question-suggestions 2024 年 4 月 3 日 这一策略唤起了IBM沃森率先采用的一项技术&#xff1a;消除歧义。面对用户模糊不清的输入&#xff0c;系统会提供大约五个或更少的选项供用户挑…

软件架构风格_3.以数据为中心的体系结构风格

以数据为中心的体系结构风格主要包括仓库体系结构风格和黑板体系结构风格。 1.仓库体系结构风格 仓库&#xff08;Repository&#xff09;是存储和维护数据的中心场所。在仓库风格&#xff08;见图1&#xff09;中&#xff0c;有两种不同的构件&#xff1a;中央数据结构说明当…

5米分辨率数字高程模型(DEM)的制作

在现代科技的驱动下&#xff0c;地理信息系统&#xff08;GIS&#xff09;和遥感技术已经取得了惊人的进展。其中一项令人瞩目的技术就是5米分辨率数字高程模型&#xff08;DEM&#xff09;的制作&#xff0c;它是基于多颗高分辨率卫星数据为原始数据&#xff0c;借助智能立体模…

Android 性能优化之黑科技开道(一)

1. 缘起 在开发电视版智家 App9.0 项目的时候&#xff0c;发现了一个性能问题。电视系统原本剩余的可用资源就少&#xff0c;而随着 9.0 功能的进一步增多&#xff0c;特别是门铃、门锁、多路视频同屏监控后等功能的增加&#xff0c;开始出现了卡顿情况。 经过调研分析发现有…

Apache DolphinScheduler 【安装部署】

前言 今天来学习一下 DolphinScheduler &#xff0c;这是一个任务调度工具&#xff0c;现在用的比较火爆。 1、安装部署 1.0、准备工作 1.0.1、集群规划 dolphinscheduler 比较吃内存&#xff0c;所以尽量给 master 节点多分配一点内存&#xff0c;桌面和虚拟机里能关的应用…

P2249 【深基13.例1】查找 (二分)

题目链接 代码&#xff1a; #include<algorithm> #include<iostream> #include<cstring> #include<queue> #include<cmath>using namespace std; //就是找左端点&#xff0c;没有输出-1 int n; int q; int a[1000010];int main() {scanf("…

Qt QML的枚举浅用

QML的枚举用法 序言概念命名规则在QML定义枚举的规范 用法QML的枚举定义方法供QML调用的&#xff0c;C的枚举定义方法 序言 概念 QML的枚举和C的其实差不多&#xff0c;但是呢&#xff0c;局限比较多&#xff0c;首先不能在main.qml里定义&#xff0c;也不能在子项中定义。 …

Java入门教程||Java 多线程编程

Java 多线程编程 Java 给多线程编程提供了内置的支持。一个多线程程序包含两个或多个能并发运行的部分。程序的每一部分都称作一个线程&#xff0c;并且每个线程定义了一个独立的执行路径。 多线程是多任务的一种特别的形式。多线程比多任务需要更小的开销。 这里定义和线程…

晶核养号攻略,小白必读攻略!

晶核手游作为一款深受玩家喜爱的游戏&#xff0c;养号是玩家们在游戏中常常会碰到的问题之一。在这个攻略中&#xff0c;我们将为新手玩家们提供一些养号的建议和技巧&#xff0c;帮助他们更好地管理和提升自己的游戏账号。 1. 初始阶段的金币管理 在游戏初期&#xff0c;前60…

四信AI智能视频边缘分析盒+传感云平台,开启食品安全智慧监管新模式

方案背景 民以食为天&#xff0c;食品是人类生存必备的物质之一&#xff0c;食品生产安全关乎每个人的生命健康与社会可持续发展。在食品生产过程中&#xff0c;如何实现安全、健康生产是监管机构首要考虑因素&#xff0c;也是当今社会必须共同关注与努力的方向。 监管机构必…

C语言中的数组与函数指针:深入解析与应用

文章目录 一、引言二、数组的定义1、数组的定义与初始化2、char*与char[]的区别1. 存储与表示2. 修改内容3. 作为函数参数 三、字符串指针数组1. 定义与概念2. 使用示例3. 内存管理 四、从字符串指针数组到函数指针的过渡1、字符串指针数组的应用场景2、函数指针的基本概念3、如…

ETL工具-nifi干货系列 第八讲 处理器PutDatabaseRecord 写数据库(详细)

1、本节通过一个小例子来讲解下处理器PutDatabaseRecord&#xff0c;该处理器的作用是将数据写入数据库。 如下流程通过处理器GenerateFlowFile 生成数据&#xff0c;然后通过处理器JoltTransformJSON转换结构&#xff0c;最后通过处理器PutDatabaseRecord将数据写入数据库。如…

C++输出格式控制

setprecision(n)可控制输出流显示浮点数的数字个数。C默认的流输出数值有效位是6&#xff0c;所以不管数据是多少&#xff0c;都只输出六位。如果setprecision(n)与setiosflags(ios::fixed)或者setiosflags(ios_base::fixed)合用&#xff0c;可以控制小数点右边的数字个数。set…

4 月 8 日至 9 日 ICP Hacker House 邀你共赴 IC 生态项目开发新风口

为了更好地探索区块链技术前沿&#xff0c;体验作为全面智能合约云平台的互联网计算机&#xff08;Internet Computer Protocol&#xff09;&#xff0c;将数据、内容、计算和用户体验全部托管于链上&#xff0c;IC 生态致力于推动去中心化互联网的深度发展&#xff0c;并将更安…