0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

HarmonyOS開發(fā)案例:【購物車app】

jf_46214456 ? 來源:jf_46214456 ? 作者:jf_46214456 ? 2024-05-14 18:19 ? 次閱讀

| ---------------------------------------------------------------------------------------- |# 概述

OpenHarmony ArkUI框架提供了豐富的動(dòng)畫組件和接口,開發(fā)者可以根據(jù)實(shí)際場(chǎng)景和開發(fā)需求,選用豐富的動(dòng)畫組件和接口來實(shí)現(xiàn)不同的動(dòng)畫效果。

本Codelab中,我們會(huì)構(gòu)建一個(gè)簡(jiǎn)易的購物應(yīng)用。應(yīng)用包含兩級(jí)頁面,分別是主頁(“商品瀏覽”頁簽、“購物車”頁簽、“我的”頁簽)和商品詳情頁面。效果如下圖所示:

代碼結(jié)構(gòu)解讀

本篇Codelab只對(duì)核心代碼進(jìn)行講解,首先來介紹下整個(gè)工程的代碼結(jié)構(gòu):

  • model:存放封裝好的數(shù)據(jù)實(shí)體。
    • ArsData:我的頁簽相關(guān)參數(shù)實(shí)體。
    • GoodsData:商品列表頁商品實(shí)體。
    • GoodsDataModels:各種實(shí)體的具體數(shù)據(jù)以及獲取數(shù)據(jù)的方法。
    • Menu:我的頁簽菜單實(shí)體。
  • pages:存放頁面。
    • HomePage:應(yīng)用主頁面,包含商品列表頁簽。
    • MyPage:我的頁簽。
    • ShoppingCartPage:購物車頁簽。
    • ShoppingDetail:商品詳情頁。
  • resources :存放工程使用到的資源文件。
    • resources/base/media:存放工程中使用的圖片資源。
  • config.json:配置文件。
  • 鴻蒙開發(fā)指導(dǎo)文檔:[gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md]

搭建OpenHarmony環(huán)境

完成本篇Codelab我們首先要完成開發(fā)環(huán)境的搭建,本示例以Hi3516DV300開發(fā)板為例,參照以下步驟進(jìn)行:

  1. [獲取OpenHarmony系統(tǒng)版本]:標(biāo)準(zhǔn)系統(tǒng)解決方案(二進(jìn)制)
    以3.0版本為例:
  2. 搭建燒錄環(huán)境
    1. [完成DevEco Device Tool的安裝]
    2. [完成Hi3516開發(fā)板的燒錄]
  3. 搭建開發(fā)環(huán)境
    1. 開始前請(qǐng)參考[工具準(zhǔn)備],完成DevEco Studio的安裝和開發(fā)環(huán)境配置。
    2. 開發(fā)環(huán)境配置完成后,請(qǐng)參考[使用工程向?qū)創(chuàng)建工程(模板選擇“Empty Ability”),選擇JS或者eTS語言開發(fā)。
    3. 工程創(chuàng)建完成后,選擇使用[真機(jī)進(jìn)行調(diào)測(cè)]。
    4. HarmonyOS與OpenHarmony鴻蒙文檔籽料:mau123789是v直接拿

搜狗高速瀏覽器截圖20240326151344.png

構(gòu)建商品列表頁簽

在本節(jié)中,我們將完成商品列表頁簽的設(shè)計(jì),效果圖如下:

從效果圖可以看出,商品列表頁簽主要由三個(gè)部分組成:

  1. 頂部的Tabs組件。
  2. 中間TabContent組件內(nèi)包含List組件。其中List組件的item是一個(gè)水平布局,由一個(gè)垂直布局和一個(gè)Image組件組成;item中的垂直布局由3個(gè)Text組件組成。
  3. 底部的導(dǎo)航頁簽navigation組件。

實(shí)現(xiàn)步驟如下:

  1. 在pages目錄下面新建一個(gè)ETS Page,命名為HomePage.ets,在config.json文件的pages屬性中會(huì)自動(dòng)添加“pages/HomePage”頁面路由。

說明:

  • 頁面文件名不能使用組件名稱,比如:Text.ets、Button.ets等。
  • 每個(gè)頁面文件中必須包含入口組件。
  1. 新建與pages文件夾同級(jí)的model文件夾,并在model目錄下新建ArsData.ets、GoodsData.ets、Menu.ets和GoodsDataModels.ets文件,其中ArsData.ets、GoodsData.ets、Menu.ets是數(shù)據(jù)實(shí)體類,GoodsDataModels.ets是存放這三種實(shí)體數(shù)據(jù)集合,并定義了獲取各種數(shù)據(jù)集合的方法。數(shù)據(jù)實(shí)體包含實(shí)體的屬性和構(gòu)造方法,可通過new ArsData(string,string) 來獲取ArsData對(duì)象,ArsData.ets內(nèi)容如下:

    let NextId = 0;
    export class ArsData {
      id: string;
      title: string;
      content: string;
    
      constructor(title: string, content: string) {
        this.id = `${NextId++}`;
        this.title = title;
        this.content = content;
      }
    }
    

    GoodsData.ets代碼如下:

    let NextId = 0;
    export class GoodsData {
      id: string;
      title: string;
      content: string;
      price: number;
      imgSrc: Resource;
    
      constructor(title: string, content: string, price: number, imgSrc: Resource) {
        this.id = `${NextId++}`;
        this.title = title;
        this.content = content;
        this.price = price;
        this.imgSrc = imgSrc;
      }
    }
    

    一個(gè)文件中可以包含多個(gè)class ,Menu.ets中就包含了Menu類和ImageItem類,Menu.ets代碼如下

    let NextId = 0;
    export class Menu {
      id: string;
      title: string;
      num: number;
    
      constructor(title: string, num: number) {
        this.id = `${NextId++}`;
        this.title = title;
        this.num = num;
      }
    }
    
    export class ImageItem {
      id: string;
      title: string;
      imageSrc: Resource;
    
      constructor(title: string, imageSrc: Resource) {
        this.id = `${NextId++}`;
        this.title = title;
        this.imageSrc = imageSrc;
      }
    }
    

    GoodsDataModels.ets代碼如下:

    import {GoodsData} from './GoodsData'
    
    import {Menu, ImageItem} from './Menu'
    import {ArsData} from './ArsData'
    //獲取商品列表數(shù)據(jù)
    export function initializeOnStartup(): Array< GoodsData > {
      let GoodsDataArray: Array< GoodsData > = []
      GoodsComposition.forEach(item = > {
        console.log(item.title);
        GoodsDataArray.push(new GoodsData(item.title, item.content, item.price, item.imgSrc));
      })
      return GoodsDataArray;
    }
    //獲取底部默認(rèn)圖片列表數(shù)據(jù)
    export function getIconPath(): Array< string > {
      let IconPath: Array< string > = ['nav/icon-buy.png','nav/icon-shopping-cart.png','nav/icon-my.png']
    
      return IconPath;
    }
    //獲取選中后圖片列表數(shù)據(jù)
    export function getIconPathSelect(): Array< string > {
      let IconPathSelect: Array< string > = ['nav/icon-home.png','nav/icon-shopping-cart-select.png','nav/icon-my-select.png']
    
      return IconPathSelect;
    }
    //獲取商品詳情頁圖片詳情列表
    export function getDetailImages(): Array< string > {
      let detailImages: Array< string > = ['computer/computer1.png','computer/computer2.png','computer/computer3.png','computer/computer4.png','computer/computer5.png','computer/computer6.png']
    
      return detailImages;
    }
    
    //獲取菜單數(shù)據(jù)列表
    export function getMenu(): Array< Menu > {
      let MenuArray: Array< Menu > = []
      MyMenu.forEach(item = > {
        MenuArray.push(new Menu(item.title,item.num));
      })
      return MenuArray;
    }
    //獲取MyTrans數(shù)據(jù)列表
    export function getTrans(): Array< ImageItem > {
      let ImageItemArray: Array< ImageItem > = []
      MyTrans.forEach(item = > {
        ImageItemArray.push(new ImageItem(item.title,item.imageSrc));
      })
      return ImageItemArray;
    }
    //獲取More數(shù)據(jù)列表
    export function getMore(): Array< ImageItem > {
      let ImageItemArray: Array< ImageItem > = []
      MyMore.forEach(item = > {
        ImageItemArray.push(new ImageItem(item.title,item.imageSrc));
      })
      return ImageItemArray;
    }
    //獲取參數(shù)列表
    export function getArs(): Array< ArsData > {
      let ArsItemArray: Array< ArsData > = []
      ArsList.forEach(item = > {
        ArsItemArray.push(new ArsData(item.title,item.content));
      })
      return ArsItemArray;
    }
    //數(shù)據(jù)集合部分
    ...
    
  2. 在HomePage.ets文件中創(chuàng)建商品列表頁簽相關(guān)的組件,其中GoodsHome效果圖如下:

    代碼如下:

    @Component
    @Component
    struct GoodsHome {
      private goodsItems: GoodsData[]
    
      build() {
        Column() {
          Tabs() {
            TabContent() {
              GoodsList({ goodsItems: this.goodsItems });
            }
            .tabBar("Top Sellers")
            .backgroundColor(Color.White)
    
            TabContent() {
              GoodsList({ goodsItems: this.goodsItems });
            }
            .tabBar("Recommended")
            .backgroundColor(Color.White)
    
            TabContent() {
              GoodsList({ goodsItems: this.goodsItems });
            }
            .tabBar("Lifestyle")
            .backgroundColor(Color.White)
    
            TabContent() {
              GoodsList({ goodsItems: this.goodsItems });
            }
            .tabBar("Deals")
            .backgroundColor(Color.White)
          }
          .barWidth(540)
          .barHeight(50)
          .scrollable(true)
          .barMode(BarMode.Scrollable)
          .backgroundColor('#007DFF')
          .height('100%')
        }
        .alignItems(HorizontalAlign.Start)
      }
    }
    

    在GoodsHome中使用Tabs組件,在Tabs組件中設(shè)置4個(gè)TabContent,給每個(gè)TabContent設(shè)置tabBar屬性,并設(shè)置TabContent容器中的內(nèi)容GoodsList組件,GoodsList組件效果圖如下:

    代碼如下:

    @Component
    struct GoodsList {
      private goodsItems: GoodsData[]
    
      build() {
        Column() {
          List() {
            ForEach(this.goodsItems, item = > {
              ListItem() {
                GoodsListItem({ goodsItem: item })
              }
            }, item = > item.id.toString())
          }
          .height('100%')
          .width('100%')
          .align(Alignment.Top)
          .margin({top: 5})
        }
      }
    }
    

    在GoodsList組件中遍歷商品數(shù)據(jù)集合,ListItem組件中設(shè)置組件內(nèi)容,并使用Navigator組件給每個(gè)Item設(shè)置頂級(jí)跳轉(zhuǎn)路由,GoodsListItem組件效果圖如下:

    代碼如下:

    @Component
    struct GoodsListItem {
      private goodsItem: GoodsData
    
      build() {
        Navigator({ target: 'pages/ShoppingDetail' }) {
          Row() {
            Column() {
              Text(this.goodsItem.title)
                .fontSize(18)
              Text(this.goodsItem.content)
                .fontSize(14)
              Text('¥' + this.goodsItem.price)
                .fontSize(18)
                .fontColor(Color.Red)
            }
            .height(130)
            .width('60%')
            .margin({ left: 20 })
            .alignItems(HorizontalAlign.Start)
    
            Image(this.goodsItem.imgSrc)
              .objectFit(ImageFit.ScaleDown)
              .height(130)
              .width('30%')
              .renderMode(ImageRenderMode.Original)
              .margin({ right: 10, left: 10 })
    
          }
          .backgroundColor(Color.White)
    
        }
        .params({ goodsData: this.goodsItem })
        .margin({ right: 5 })
      }
    }
    
  3. 在HomePage.ets中創(chuàng)建文件入口組件(Index)以及底部頁簽導(dǎo)航組件(Navigation),導(dǎo)入需要使用到的數(shù)據(jù)實(shí)體類以及需要使用的方法和組件,每個(gè)page文件都必須包含一個(gè)入口組件,使用@Entry修飾,HomePage文件中的入口組件(Index)代碼如下:

    import { GoodsData, IconImage } from '../model/GoodsData'
    import { initializeOnStartup, getIconPath, getIconPathSelect } from '../model/GoodsDataModels'
    import { ShoppingCart } from './ShoppingCartPage.ets'
    import { MyInfo } from './MyPage.ets'
    import router from '@system.router';
    
    @Entry
    @Component
    struct Index {
      @Provide currentPage: number = 1
      private goodsItems: GoodsData[] = initializeOnStartup()
      @State Build: Array< Object > = [
        {
          icon: $r('app.media.icon_home'),
          icon_after: $r('app.media.icon_buy1'),
          text: '首頁',
          num: 0
        },
        {
          icon: $r('app.media.icon_shopping_cart'),
          icon_after: $r('app.media.icon_shopping_cart_select'),
          text: '購物車',
          num: 1
        },
        {
          icon: $r('app.media.icon_my'),
          icon_after: $r('app.media.icon_my_select'),
          text: '我的',
          num: 2
        }
      ]
    
      @Builder NavigationToolbar() {
        Flex({direction:FlexDirection.Row,wrap:FlexWrap.NoWrap,justifyContent:FlexAlign.SpaceAround}) {
          ForEach(this.Build, item = > {
            Column() {
              Image(this.currentPage == item.num ? item.icon_after : item.icon)
                .width(25)
                .height(25)
              Text(item.text)
                .fontColor(this.currentPage == item.num ? "#ff7500" : "#000000")
            }
            .onClick(() = > {
              this.currentPage = item.num
            })
          })
        }
      }
    
      build() {
        Column() {
          Navigation() {
            Flex() {
              if (this.currentPage == 0) {
                GoodsHome({ goodsItems: this.goodsItems })
              }
              if (this.currentPage == 1) {
                ShoppingCart() //購物車列表
              }
              if (this.currentPage == 2) {
                MyInfo() //我的
              }
            }
            .width('100%')
            .height('100%')
          }
          .toolBar(this.NavigationToolbar)
          .title("購物車")
          .hideTitleBar(this.currentPage == 1 ? false : true)
          .hideBackButton(true)
        }
      }
    }
    

    從入口組件的代碼中可以看出,我們定義了一個(gè)全局變量currentPage ,當(dāng)currentPage發(fā)生變化的時(shí)候,會(huì)顯示不同的頁簽。在入口組件中,通initializeOnStartup獲取商品列表數(shù)據(jù)(goodsItems)并傳入GoodsHome組件中。效果圖如下:

構(gòu)建購物車頁簽

從上面效果圖可以看出,主界面購物車頁簽主要由下面三部分組成:

  1. 頂部的title,由Navigation組件title屬性設(shè)置。
  2. 中間的List組件,其中List組件的item是一個(gè)水平的布局內(nèi)包含一個(gè)toggle組件,一個(gè)Image組件和一個(gè)垂直布局,其item中的垂直布局是由2個(gè)Text組件組成。
  3. 底部一個(gè)水平布局包含兩個(gè)Text組件。

在本任務(wù)中我們主要是構(gòu)建一個(gè)購物車頁簽,給商品列表的每個(gè)商品設(shè)置一個(gè)單選框,可以選中與取消選中,底部Total值也會(huì)隨之增加或減少,點(diǎn)擊Check Out時(shí)會(huì)觸發(fā)彈窗。下面我們來完成ShoppingCart頁簽。

  1. 在pages目錄下面新建一個(gè)ETS Page ,命名為ShoppingCart.ets,config.json文件pages屬性中也會(huì)自動(dòng)添加“pages/ShoppingCart”頁面路由。

  2. 在ShoppingCartPage.ets文件中添加入口組件(ShoppingCart),并導(dǎo)入需要使用到的數(shù)據(jù)實(shí)體類、方法和組件。ShoppingCart組件代碼如下:

    import {GoodsData} from '../model/GoodsData'
    import {initializeOnStartup} from '../model/GoodsDataModels'
    import prompt from '@system.prompt';
    
    @Entry
    @Component
     export struct ShoppingCart {
      @Provide totalPrice: number = 0
      private goodsItems: GoodsData[] = initializeOnStartup()
    
      build() {
        Column() {
          ShopCartList({ goodsItems: this.goodsItems });
          ShopCartBottom()
        }
        .height('100%')
        .width('100%')
        .alignItems(HorizontalAlign.Start)
      }
    }
    
  3. 新建ShopCartList組件用于存放購物車商品列表,ShopCartList組件效果圖如下:

    代碼如下:

    @Component
    struct ShopCartList {
      private goodsItems: GoodsData[]
    
      build() {
        Column() {
          List() {
            ForEach(this.goodsItems, item = > {
              ListItem() {
                ShopCartListItem({ goodsItem: item })
              }
            }, item = > item.id.toString())
          }
          .height('100%')
          .width('100%')
          .align(Alignment.Top)
          .margin({ top: 5 })
        }
        .height('90%')
      }
    }
    

    在ShopCartListItem中使用Toggle的單選框類型來實(shí)現(xiàn)每個(gè)item的選擇和取消選擇,在Toggle的onChage事件中來改變totalPrice的數(shù)值。ShopCartListItem組件效果圖如下:

    代碼如下:

    @Component
    struct ShopCartListItem {
      @Consume totalPrice: number
      private goodsItem: GoodsData
    
      build() {
        Row() {
          Toggle({ type: ToggleType.Checkbox })
            .width(13)
            .height(13)
            .onChange((isOn: boolean) = > {
            if (isOn) {
              this.totalPrice += parseInt(this.goodsItem.price + '', 0)
            } else {
              this.totalPrice -= parseInt(this.goodsItem.price + '', 0)
            }
          })
          Image(this.goodsItem.imgSrc)
            .objectFit(ImageFit.ScaleDown)
            .height(130)
            .width(100)
            .renderMode(ImageRenderMode.Original)
          Column() {
            Text(this.goodsItem.title)
              .fontSize(18)
            Text('¥' + this.goodsItem.price)
              .fontSize(18)
              .fontColor(Color.Red)
          }
          .margin({left:40})
        }
        .height(100)
        .width('100%')
        .margin({ left: 20 })
        .alignItems(VerticalAlign.Center)
        .backgroundColor(Color.White)
      }
    }
    
  4. 新建ShopCartBottom組件,ShopCartBottom組件效果圖如下:

    代碼如下:

    @Component
    struct ShopCartBottom {
      @Consume totalPrice: number
    
      build() {
        Row() {
          Text('Total:  ¥' + this.totalPrice)
            .fontColor(Color.Red)
            .fontSize(18)
            .margin({ left: 20 })
            .width(150)
          Text('Check Out')
            .fontColor(Color.Black)
            .fontSize(18)
            .margin({ right: 20, left: 180 })
            .onClick(() = > {
            prompt.showToast({
              message: 'Checking Out',
              duration: 10,
              bottom: 100
            })
          })
        }
        .height(30)
        .width('100%')
        .backgroundColor('#FF7FFFD4')
        .alignItems(VerticalAlign.Bottom)
      }
    }
    

構(gòu)建我的頁簽

從上面效果圖可以看出,主界面我的頁簽主要由下面四部分組成:

  1. 頂部的水平布局。
  2. 頂部下面的文本加數(shù)字的水平List。
  3. My Transactio模塊,圖片加文本的水平List。
  4. More模塊,圖片加文本的Grid。

在本任務(wù)中,我們構(gòu)建主頁我的頁簽,主要可以劃分成下面幾步:

  1. 在pages目錄下面新建一個(gè)ETS Page 命名為MyPage.ets,在config.json文件pages屬性中也會(huì)自動(dòng)添加“pages/MyPage”頁面路由。

  2. 在MyPage.ets文件中添加入口組件(MyInfo),組件內(nèi)容如下:

    import {getMenu,getTrans,getMore} from '../model/GoodsDataModels'
    import {Menu, ImageItem} from '../model/Menu'
    @Entry
    @Component
    export struct MyInfo {
      build() {
        Column() {
          Row() {
            Image($r('app.media.icon_user'))
              .objectFit(ImageFit.Contain)
              .height(50)
              .width(50)
              .margin({left:10})
              .renderMode(ImageRenderMode.Original)
            Column() {
              Text('John Doe')
                .fontSize(15)
              Text('Member Name : John Doe                     >')
                .fontSize(15)
            }
            .height(60)
            .margin({ left: 20, top: 10 })
            .alignItems(HorizontalAlign.Start)
          }
    
          TopList()
          MyTransList()
          MoreGrid()
    
        }
        .alignItems(HorizontalAlign.Start)
        .width('100%')
        .height('100%')
        .flexGrow(1)
      }
    }
    

    入口組件中還包含TopList,MyTransList和MoreGrid三個(gè)子組件。

  3. 在MyPage.ets文件中新建TopList組件,效果圖如下:

    代碼如下:

    @Component
    struct TopList {
      private menus: Menu1[] = getMenu()
    
      build() {
        Row() {
          List() {
            ForEach(this.menus, item = > {
              ListItem() {
                MenuItem({ menu: item })
              }
            }, item = > item.id.toString())
          }
          .height('100%')
          .width('100%')
          .margin({ top: 5,left: 10})
          .edgeEffect(EdgeEffect.None)
          .listDirection(Axis.Horizontal)
        }
        .width('100%')
        .height(50)
      }
    }
    

    getMenu()方法在上文中已有定義,是獲取菜單列表的方法,TopList的子組件MenuItem內(nèi)容如下:

    @Component
    struct MenuItem {
      private menu: Menu1
    
      build() {
        Column() {
          Text(this.menu.title)
            .fontSize(15)
          Text(this.menu.num + '')
            .fontSize(13)
    
        }
        .height(50)
        .width(100)
        .margin({ left: 8, right: 8 })
        .alignItems(HorizontalAlign.Start)
        .backgroundColor(Color.White)
      }
    }
    
  4. 在MyPage.ets文件中新建MyTransList組件和MoreGrid組件,MyTransList組件效果如如下:

    代碼如下:

    @Component
    struct MyTransList {
      private imageItems: ImageItem[] = getTrans()
    
      build() {
        Column() {
          Text('My Transaction')
            .fontSize(20)
            .margin({ left: 10 })
            .width('100%')
            .height(30)
          Row() {
            List() {
              ForEach(this.imageItems, item = > {
                ListItem() {
                  DataItem({ imageItem: item })
                }
              }, item = > item.id.toString())
            }
            .height(70)
            .width('100%')
            .edgeEffect(EdgeEffect.None)
            .margin({ top: 5 })
            .padding({ left: 16, right: 16 })
            .listDirection(Axis.Horizontal)
          }
        }
        .height(120)
      }
    }
    

    MoreGrid組件效果圖如下:

    代碼如下:

    @Component
    struct MoreGrid {
      private gridRowTemplate: string = ''
      private imageItems: ImageItem[] = getMore()
      private heightValue: number
    
      aboutToAppear() {
        var rows = Math.round(this.imageItems.length / 3);
        this.gridRowTemplate = '1fr '.repeat(rows);
        this.heightValue = rows * 75;
      }
    
      build() {
        Column() {
          Text('More')
            .fontSize(20)
            .margin({ left: 10 })
            .width('100%')
            .height(30)
          Scroll() {
            Grid() {
              ForEach(this.imageItems, (item: ImageItem) = > {
                GridItem() {
                  DataItem({ imageItem: item })
                }
              }, (item: ImageItem) = > item.id.toString())
            }
            .rowsTemplate(this.gridRowTemplate)
            .columnsTemplate('1fr 1fr 1fr')
            .columnsGap(8)
            .rowsGap(8)
            .height(this.heightValue)
          }
          .padding({ left: 16, right: 16 })
        }
        .height(400)
      }
    }
    

    在MyTransList和MoreGrid組件中都包含子組件DataItem,為避免的重復(fù)代碼,可以把多次要用到的結(jié)構(gòu)體組件化,這里的結(jié)構(gòu)體就是圖片加上文本的上下結(jié)構(gòu)體,DataItem組件內(nèi)容如下:

    @Component
    struct DataItem {
      private imageItem: ImageItem
    
      build() {
        Column() {
          Image(this.imageItem.imageSrc)
            .objectFit(ImageFit.Contain)
            .height(50)
            .width(50)
            .renderMode(ImageRenderMode.Original)
          Text(this.imageItem.title)
            .fontSize(15)
    
        }
        .height(70)
        .width(150)
        .margin({ left: 10, right: 10 })
        .backgroundColor(Color.White)
      }
    }
    

構(gòu)建商品詳情頁面

從上面效果圖可以看出,商品詳情頁面主要由下面五部分組成:

  1. 頂部的返回欄。
  2. Swiper組件。
  3. 中間多個(gè)Text組件組成的布局。
  4. 參數(shù)列表。
  5. 底部的Buy。

在本任務(wù)中,把上面每一部分都封裝成一個(gè)組件,然后再放到入口組件內(nèi),當(dāng)點(diǎn)擊頂部返回圖標(biāo)時(shí)返回到主頁面的商品列表頁簽,點(diǎn)擊底部Buy時(shí),會(huì)觸發(fā)進(jìn)度條彈窗

  1. 在pages目錄下面新建一個(gè)ETS Page, 命名為ShoppingDetail.ets,config.json文件pages屬性中也會(huì)自動(dòng)添加“pages/ShoppingDetail”頁面路由。

  2. 在ShoppingDetail.ets文件中創(chuàng)建入口組件,組件內(nèi)容如下:

    @Entry
    @Component
    struct ShoppingDetail {
      private arsItems: ArsData[] = getArs()
    
      build() {
        Column() {
          DetailTop()
          Scroll() {
            Column() {
              SwiperTop()
              DetailText()
              DetailArsList({ arsItems: this.arsItems })
              Image($r('app.media.computer1'))
                .height(220)
                .width('100%')
                .margin({ top: 30 })
              Image($r('app.media.computer2'))
                .height(220)
                .width('100%')
                .margin({ top: 30 })
              Image($r('app.media.computer3'))
                .height(220)
                .width('100%')
                .margin({ top: 30 })
              Image($r('app.media.computer4'))
                .height(220)
                .width('100%')
                .margin({ top: 30 })
              Image($r('app.media.computer5'))
                .height(220)
                .width('100%')
                .margin({ top: 30 })
              Image($r('app.media.computer6'))
                .height(220)
                .width('100%')
                .margin({ top: 30 })
            }
            .width('100%')
            .flexGrow(1)
          }
          .scrollable(ScrollDirection.Vertical)
    
          DetailBottom()
        }
        .height('90%')
        .width('100%')
      }
    }
    

    其中頂部DetailTop組件效果圖如下:

    代碼如下:

    @Component
    struct DetailTop {
      build() {
        Column() {
          Row() {
            Image($r('app.media.icon_return'))
              .height(40)
              .width(40)
              .margin({left: 20})
              .onClick(() = > {
                router.push({
                  uri: "pages/HomePage"
                })
              })
    
          }
          .width('100%')
          .height(35)
          .backgroundColor('#FF87CEEB')
        }
        .width('100%')
        .height(40)
      }
    }
    
  3. SwiperTop組件效果圖如下:

    代碼如下:

    @Component
    struct SwiperTop {
      build() {
        Column() {
          Swiper() {
            Image($r('app.media.computer1'))
              .height(220)
              .width('100%')
            Image($r('app.media.computer2'))
              .height(220)
              .width('100%')
            Image($r('app.media.computer3'))
              .height(220)
              .width('100%')
            Image($r('app.media.computer4'))
              .height(220)
              .width('100%')
            Image($r('app.media.computer5'))
              .height(220)
              .width('100%')
            Image($r('app.media.computer6'))
              .height(220)
              .width('100%')
          }
          .index(0)
          .autoPlay(true)
          .interval(3000)
          .indicator(true)
          .loop(true)
          .height(250)
          .width('100%')
        }
        .height(250)
        .width('100%')
      }
    }
    
  4. DetailText組件效果圖如下:

    代碼如下:

    @Component
    struct DetailText {
      build() {
        Column() {
          Row() {
            Image($r('app.media.icon_promotion'))
              .objectFit(ImageFit.Contain)
              .height(30)
              .width(30)
              .margin({ left: 10 })
            Text('Special Offer: ¥9999')
              .fontColor(Color.White)
              .fontSize(20)
              .margin({ left: 10 })
    
          }
          .width('100%')
          .height(35)
          .backgroundColor(Color.Red)
    
          Column() {
            Text('New Arrival: HUAWEI MateBook X Pro 2021')
              .fontSize(18)
              .margin({ left: 10 })
              .alignSelf(ItemAlign.Start)
            Text('13.9-Inch, 11th Gen Intel? Core? i7, 16 GB of Memory, 512 GB of Storage, Ultra-slim Business Laptop, 3K FullView Display, Multi-screen 
                              Collaboration, Emerald Green')
              .fontSize(14)
              .margin({ left: 10 })
            Row() {
              Image($r('app.media.icon_buy'))
                .objectFit(ImageFit.Contain)
                .height(30)
                .width(30)
                .margin({ left: 10 })
              Text('Limited offer')
                .fontSize(15)
                .fontColor(Color.Red)
                .margin({ left: 100 })
    
            }
            .backgroundColor(Color.Pink)
            .width('100%')
            .height(45)
            .margin({ top: 10 })
    
            Text(' Shipment:         2-day shipping')
              .fontSize(13)
              .fontColor(Color.Red)
              .margin({ left: 10, top: 5 })
              .alignSelf(ItemAlign.Start)
            Text('    Ship To:         Hubei,Wuhan,China')
              .fontSize(13)
              .fontColor(Color.Red)
              .margin({ left: 10, top: 5 })
              .alignSelf(ItemAlign.Start)
              .onClick(() = > {
                prompt.showDialog({ title: 'select address', })
    
              })
            Text('Guarantee:         Genuine guaranteed')
              .fontSize(13)
              .margin({ left: 10, top: 5 })
              .alignSelf(ItemAlign.Start)
          }
          .height(170)
          .width('100%')
        }
        .height(180)
        .width('100%')
      }
    }
    

    DetailArsList組件效果圖如下:

    代碼如下:

    @Component
    struct DetailArsList{
      private arsItems: ArsData[]
      build() {
        Scroll() {
          Column() {
            List() {
              ForEach(this.arsItems, item = > {
                ListItem() {
                  ArsListItem({ arsItem: item })
                }
              }, item = > item.id.toString())
            }
            .height('100%')
            .width('100%')
            .margin({ top: 5 })
            .listDirection(Axis.Vertical)
          }
          .height(200)
        }
      }
    }
    

    ArsListItem組件代碼如下:

    @Component
    struct ArsListItem {
      private arsItem: ArsData
    
      build() {
        Row() {
          Text(this.arsItem.title + " :")
            .fontSize(11)
            .margin({ left: 20 })
            .flexGrow(1)
          Text(this.arsItem.content)
            .fontSize(11)
            .margin({ right: 20 })
    
        }
        .height(14)
        .width('100%')
        .backgroundColor(Color.White)
      }
    }
    
  5. DetailBottom組件效果圖如下:

    代碼如下:

    @Component
    struct DetailBottom {
      @Provide
      private value: number= 1
      dialogController: CustomDialogController = new CustomDialogController({
        builder: DialogExample({ action: this.onAccept }),
        cancel: this.existApp,
        autoCancel: true
      });
    
      onAccept() {
    
      }
    
      existApp() {
    
      }
    
      build() {
        Column() {
          Text('Buy')
            .width(40)
            .height(25)
            .fontSize(20)
            .fontColor(Color.White)
            .onClick(() = > {
              this.value = 1
              this.dialogController.open()
            })
        }
        .alignItems(HorizontalAlign.Center)
        .backgroundColor(Color.Red)
        .width('100%')
        .height('10%')
      }
    }
    

    DialogExample自定義彈窗組件效果圖如下:

    代碼如下:

    @CustomDialog
    struct DialogExample {
      @Consume
      private value: number
      controller: CustomDialogController;
      action: () = > void;
    
      build() {
        Column() {
          Progress({ value: this.value++ >= 100 ? 100 : this.value, total: 100, style: ProgressStyle.Capsule })
            .height(50)
            .width(100)
            .margin({ top: 5 })
    
        }
        .height(60)
        .width(100)
      }
    }
    

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 鴻蒙
    +關(guān)注

    關(guān)注

    57

    文章

    2302

    瀏覽量

    42689
  • HarmonyOS
    +關(guān)注

    關(guān)注

    79

    文章

    1966

    瀏覽量

    29962
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    asp.net購物車系統(tǒng)源代碼

    用ajax實(shí)現(xiàn)電子商務(wù)網(wǎng)站中的購物車系統(tǒng)+源碼 asp.net購物車系統(tǒng)源代碼
    發(fā)表于 10-14 13:00

    智能自助服務(wù)超市購物車

    為解決超市購物結(jié)算等候時(shí)間過長(zhǎng)的問題,提出一款智能購物車的方案:用戶在超市購物后將商品條碼信息掃描錄入到購物車中,并存儲(chǔ),結(jié)算時(shí)通過藍(lán)牙將所有購物
    發(fā)表于 11-16 22:47

    【OK210申請(qǐng)】基于RFID的智能購物車

    技術(shù)實(shí)現(xiàn)一個(gè)超市智能購物車系統(tǒng),實(shí)現(xiàn)購物車,服務(wù)器,商品和手機(jī)等設(shè)備的智能互連,具有很好的技術(shù)鍛煉價(jià)值和應(yīng)用前景。開發(fā)中要用到ARM板子來跑嵌入式系統(tǒng)。項(xiàng)目描述:目前國(guó)內(nèi)外很多大型超市以及商場(chǎng)都是采用
    發(fā)表于 06-25 15:43

    沃爾瑪計(jì)劃將超市購物車變?yōu)橹悄軝C(jī)器人

      多家媒體報(bào)道稱,沃爾瑪正計(jì)劃將智能購物助手集成至超市購物車。  沃爾瑪正在與Five Elements Robotics展開合作,幫助消費(fèi)者更輕松地推動(dòng)購物車,而購物車還可以向消費(fèi)
    發(fā)表于 06-24 16:17

    新手上路,如何做一個(gè)點(diǎn)菜系統(tǒng),點(diǎn)好的菜可以放到購物車中結(jié)賬

    現(xiàn)在想做一個(gè)點(diǎn)菜的一個(gè)系統(tǒng),點(diǎn)好一個(gè)菜后可以放到購物車中,最后點(diǎn)擊購物車進(jìn)行結(jié)賬,思路不清楚
    發(fā)表于 02-10 11:05

    【NXP LPC54110試用申請(qǐng)】一種基于語音控制的購物車控制系統(tǒng)

    項(xiàng)目名稱:一種基于語音控制的購物車控制系統(tǒng)試用計(jì)劃:利用語音控制的系統(tǒng)控制購物車完成前進(jìn)、后退、左轉(zhuǎn)、右轉(zhuǎn)的各項(xiàng)功能,因此可以用NXP LPC芯片的這一款54110的芯片,我相信這是一項(xiàng)基于購物車的技術(shù)領(lǐng)域的進(jìn)步!
    發(fā)表于 09-27 11:33

    【uFun試用申請(qǐng)】基于uFun的智能跟隨購物車

    項(xiàng)目名稱:基于uFun的智能跟隨購物車試用計(jì)劃:申請(qǐng)理由:本人在嵌入式領(lǐng)域和信號(hào)處理領(lǐng)域有兩年的的學(xué)習(xí)和開發(fā)經(jīng)驗(yàn),曾設(shè)計(jì)過圖書館智能管理機(jī)器人,物料搬運(yùn)機(jī)器人,室內(nèi)環(huán)境檢測(cè)與控制系統(tǒng),智能派件機(jī)器人
    發(fā)表于 03-22 18:24

    分享一個(gè)不錯(cuò)的Versa64購物車項(xiàng)目

    描述Versa64購物車完整的項(xiàng)目描述在這里:https://github.com/bwack/Versa64Cart
    發(fā)表于 07-08 08:57

    開發(fā)樣例】OpenHarmony分布式購物車

    \\entry-debug-standard-ark-signed.hap體驗(yàn)分布式購物車時(shí),需要兩個(gè)開發(fā)板,連接同一個(gè)wifi或使用網(wǎng)線連接并配置同一網(wǎng)段IP地址hdc shell ifconfig eth0 192.168.1.111 netmask
    發(fā)表于 07-29 14:17

    ajax實(shí)現(xiàn)電子商務(wù)網(wǎng)站中的購物車系統(tǒng)+源碼

    ajax實(shí)現(xiàn)電子商務(wù)網(wǎng)站中的購物車系統(tǒng)+源碼 2購物車-使用ajax(購買+刪除)
    發(fā)表于 10-14 12:57 ?37次下載

    Facebook新增加“購物車”功能

    據(jù)外媒AndroidHeadlines消息,WhatsApp日前增加了“購物車”功能,可以讓用戶更輕松地購物。這將允許用戶添加多種產(chǎn)品,并將訂單一鍵發(fā)送給商戶。
    的頭像 發(fā)表于 12-11 11:40 ?3118次閱讀

    Versa64購物車開源資料分享

    Versa64購物車
    發(fā)表于 07-01 15:04 ?2次下載
    Versa64<b class='flag-5'>購物車</b>開源資料分享

    使用evive遙控購物車

    電子發(fā)燒友網(wǎng)站提供《使用evive遙控購物車.zip》資料免費(fèi)下載
    發(fā)表于 11-11 14:53 ?0次下載
    使用evive遙控<b class='flag-5'>購物車</b>

    五步走 擁有專屬無敵購物車!

    我們的購物車功能強(qiáng)大,不只是添加產(chǎn)品和統(tǒng)一結(jié)賬,還有更多便利的工具,讓你享受快速下單的體驗(yàn)。所有產(chǎn)品現(xiàn)貨庫存,一件發(fā)貨*,下單即發(fā)貨。 注冊(cè)myDigiKey賬戶, 更可享受更完整、會(huì)員專屬的服務(wù)
    的頭像 發(fā)表于 04-06 07:45 ?457次閱讀

    智能購物車方案

    智能購物車(smart shopping cart )是一種新型的超市購物手推車,除了具備普通購物車裝載貨物的功能,還具有支持用戶自助掃碼購物,快速自助結(jié)賬離開超市,
    的頭像 發(fā)表于 07-20 18:25 ?3080次閱讀
    智能<b class='flag-5'>購物車</b>方案