【HarmonyOS应用开发——ArkTS语言】购物商城的实现【合集】

目录

😋环境配置:华为HarmonyOS开发者

📺演示效果:

📖实验步骤及方法:

一、在src/main/ets文件中创建components文件夹并在其中创建Home.ets和HomeProduct.ets文件。​编辑

二、在Home.ets文件中定义 Home 组件,进行商城主页的布局与相关功能的部署。

1. 导入模块

2. Home 组件定义

3. aboutToAppear 方法

4. build 方法(核心界面构建逻辑)

(1)整体布局结构:

(2)搜索栏部分:

(3)主体内容部分(基于 List 组件)

5. 自定义文本样式扩展函数

三、在HomePruduct.ets文件中定义 HomeProduct 组件,展示商城主页中的内容。

1. 接口定义

2. HomeProduct 组件定义

3. 组件状态定义

4. aboutToAppear 生命周期方法

5. getItem 构建函数

6. build 方法(核心界面构建逻辑)

四、在src/main/ets/pages/Index.ets文件中,定义Index 组件作为应用的入口组件。

1. 导入模块

2. Index 组件定义与入口标识

3. aboutToAppear 生命周期方法

4. 组件状态定义

5. myBuilder 构建函数

6. build 方法(核心界面构建逻辑)

👋实验小结


😋环境配置:华为HarmonyOS开发者

🎯学习小目标:实现如下的购物商城主页效果

📺演示效果:

📖实验步骤及方法:

一、在src/main/ets文件中创建components文件夹并在其中创建Home.ets和HomeProduct.ets文件。

二、在Home.ets文件中定义 Home 组件,进行商城主页的布局与相关功能的部署。

实现代码如下:

import font from '@ohos.font'
import HomeProduct from '../components/HomeProduct'
@Component
export default struct Home{aboutToAppear(): void {font.registerFont({familyName: 'myFont',familySrc: '/fonts/iconfont.ttf'})}build(){Column(){Row(){Image($r('app.media.logoCircle')).width(40)Row(){TextInput({placeholder:"搜索内容"}).layoutWeight(1).fontSize(16).backgroundColor(Color.Transparent)Text("\ue679").width(40).height('100%').backgroundColor('#fa2a83').fontFamily('myFont').fontSize(20).fontColor('#fff').fontWeight('bolder').borderRadius({topLeft:0,topRight:20,bottomLeft:0,bottomRight:20}).textAlign(TextAlign.Center)}.height(35).padding({left:5}).backgroundColor('#fff').layoutWeight(1).margin({left:3}).borderRadius(20)}.width('100%').padding({top:10,left:'10%',right:"10%",bottom:10}).backgroundColor('#0966b4')//主体内容List(){ListItem(){Swiper(){Image($r('app.media.img01'))Image($r('app.media.img02'))Image($r('app.media.img03'))Image($r('app.media.img04'))Image($r('app.media.img05'))Image($r('app.media.img06'))}.width('100%').aspectRatio(2).loop(true).autoPlay(true).interval(3000).indicator(Indicator.dot().itemWidth(10).itemHeight(10).selectedItemWidth(20).selectedItemHeight(10).color(Color.White).selectedColor(Color.Red))}ListItem(){Grid(){GridItem(){Column(){Text('\ue67d').listItem()Text('店铺').icoText()}}GridItem(){Column(){Text('\ue632').listItem()Text('陶瓷').icoText()}}GridItem(){Column(){Text('\ue61f').listItem()Text('二手书').icoText()}}GridItem(){Column(){Text('\ue652').listItem()Text('服务').icoText()}}}.width('100%').height('100%').rowsTemplate('1fr').columnsTemplate('1fr 1fr 1fr 1fr')}.width('100%').height(100).margin({top:5,bottom:5})//推荐标题ListItem(){Row(){Text('推荐好物').fontSize('100%').height(30).fontWeight('bolder').fontColor('#0966b4')Text('更多⇨').fontSize(12).fontColor('#0966b4')}.backgroundColor('#d1d1d1').justifyContent(FlexAlign.SpaceBetween).width('100%').padding(10)}ListItem(){HomeProduct()}}.layoutWeight(1).backgroundColor(Color.White)}}
}
@Extend(Text)function listItem(){.width(60).height(60).backgroundColor('#0966b4').fontFamily('myFont').fontSize(35).fontColor('#fff').borderRadius(30).textAlign(TextAlign.Center)
}
@Extend(Text)function icoText(){.fontSize(15).height(30).fontWeight('bolder')
}

该组件构建了一个具有特定布局和功能的界面,包含了搜索栏、轮播图、网格布局展示分类以及推荐好物相关展示等内容。
 

1. 导入模块
import font from '@ohos.font';
import HomeProduct from '../components/HomeProduct';

        从 @ohos.font 导入了 font 模块,可能用于字体相关的操作,比如注册自定义字体等,从后续代码中对字体注册的使用可以印证这一点。

        导入了自定义的 HomeProduct 组件,推测这个组件用于展示具体的推荐好物等相关内容,不过代码中未给出 HomeProduct 的具体实现细节。

2.Home 组件定义
import font from '@ohos.font';
import HomeProduct from '../components/HomeProduct';
        使用 @Component 装饰器将 Home 结构体标记为一个组件,意味着它可以在界面构建中被当作一个独立的 UI 单元来使用,并且按照其内部定义的 build 方法来渲染具体的界面内容。
 
3.aboutToAppear 方法
aboutToAppear(): void {font.registerFont({familyName: 'myFont',familySrc: '/fonts/iconfont.ttf'})
}

        这是一个生命周期相关的方法,在组件即将显示时被调用(根据名称和常见的组件生命周期逻辑推测)。

        它调用了 font 模块的 registerFont 方法,目的是注册一个名为 myFont 的自定义字体,字体文件来源指定为 /fonts/iconfont.ttf,这样后续就可以在组件中使用这个自定义字体来显示特定的文本样式了。
 

4.build 方法(核心界面构建逻辑)
(1)整体布局结构:

        整个界面构建基于 Column(列布局),在这个列布局内部嵌套了多个 Row(行布局)以及其他复杂的组件,来构建出最终的页面结构。

(2)搜索栏部分:
Row(){Image($r('app.media.logoCircle')).width(40)Row(){TextInput({placeholder:"搜索内容"}).layoutWeight(1).fontSize(16).backgroundColor(Color.Transparent)Text("\ue679").width(40).height('100%').backgroundColor('#fa2a83').fontFamily('myFont').fontSize(20).fontColor('#fff').fontWeight('bolder').borderRadius({topLeft:0,topRight:20,bottomLeft:0,bottomRight:20}).textAlign(TextAlign.Center)}.height(35).padding({left:5}).backgroundColor('#fff').layoutWeight(1).margin({left:3}).borderRadius(20)
}
.width('100%')
.padding({top:10,left:'10%',right:"10%",bottom:10})
.backgroundColor('#0966b4')
  • 外层 Row 作为整体搜索栏的容器,设置了一定的内边距、背景颜色、外边距等样式,并且宽度占满父容器(width('100%'))。
  • 内部首先有一个 Image 组件,显示一个宽度为 40 的图片(可能是应用的 logo 之类的元素),其资源通过 $r('app.media.logoCircle') 方式引用(具体的资源加载机制依赖于框架实现)。
  • 接着又是一个 Row,里面包含 TextInput 和 Text 组件,构建了一个常见的搜索输入框搭配搜索图标样式。
  • TextInput 用于用户输入搜索内容,设置了占位符为 "搜索内容",占一定的布局权重(layoutWeight(1))以自适应宽度,背景透明等样式。
  • Text 组件显示一个特定的图标(通过 \ue679 这个 Unicode 编码对应的图标,可能是自定义字体图标集中的一个),设置了各种样式,如背景颜色、使用注册的 myFont 字体、字体大小、颜色、加粗以及特定的圆角样式等,整体看起来像是搜索按钮的样式呈现。
(3)主体内容部分(基于 List 组件)
List(){// 轮播图相关的 ListItemListItem(){Swiper(){Image($r('app.media.img01'))Image($r('app.media.img02'))Image($r('app.media.img03'))Image($r('app.media.img04'))Image($r('app.media.img05'))Image($r('app.media.img06'))}.width('100%').aspectRatio(2).loop(true).autoPlay(true).interval(3000).indicator(Indicator.dot().itemWidth(10).itemHeight(10).selectedItemWidth(20).selectedItemHeight(10).color(Color.White).selectedColor(Color.Red))}// 网格布局分类展示的 ListItemListItem(){Grid(){GridItem(){Column(){Text('\ue67d').listItem()Text('店铺').icoText()}}// 省略其他几个 GridItem 类似结构,都是展示不同分类}.width('100%').height('100%').rowsTemplate('1fr').columnsTemplate('1fr 1fr 1fr 1fr')}.width('100%').height(100).margin({top:5,bottom:5})// 推荐标题的 ListItemListItem(){Row(){Text('推荐好物').fontSize('100%').height(30).fontWeight('bolder').fontColor('#0966b4')Text('更多⇨').fontSize(12).fontColor('#0966b4')}.backgroundColor('#d1d1d1').justifyContent(FlexAlign.SpaceBetween).width('100%').padding(10)}ListItem(){HomeProduct()}
}
.layoutWeight(1)
.backgroundColor(Color.White)
List 组件作为一个可滚动的列表容器,里面包含多个  ListItem,每个  ListItem 呈现不同的内容块。
  • 轮播图 ListItem
    • 内部的 Swiper 组件用于实现图片轮播效果,添加了多个 Image 组件(资源通过类似 $r('app.media.imgXX') 引用)。
    • Swiper 设置了宽度占满父容器、固定的宽高比(aspectRatio(2)),开启循环播放(loop(true))、自动播放(autoPlay(true))且设置了轮播间隔为 3000 毫秒,同时配置了轮播指示器(Indicator.dot() 相关配置),用于显示当前轮播图片的索引等信息,以小圆点形式呈现,并且区分了选中和未选中状态的样式。
  • 网格布局分类展示 ListItem
    • 使用 Grid 组件构建一个网格布局,里面有多个 GridItem,每个 GridItem 又包含 Column 布局,用于垂直排列图标(通过自定义字体图标对应的 Text 组件且应用 listItem 扩展样式)和对应的文字说明(应用 icoText 扩展样式),展示不同的分类,比如店铺、陶瓷等。
    • Grid 设置了宽度、高度占满父容器,以及行列模板,定义了一行四列且均匀分配空间的布局形式。
  • 推荐标题 ListItem
    • 通过 Row 布局包含两个 Text 组件,分别显示 "推荐好物"(样式上做了字体大小、加粗、颜色等设置)和 "更多⇨"(相对小一点字体且同样设置了颜色),整体 Row 设置了背景颜色、两端对齐(justifyContent(FlexAlign.SpaceBetween))以及内边距等样式,用于呈现一个推荐好物的标题栏效果,并且可以点击 "更多⇨" 可能跳转到更多推荐内容页面(具体取决于相关交互逻辑实现,代码中未体现)。

最后一个 ListItem 使用了导入的 HomeProduct 组件,用于展示具体的推荐好物详细内容,不过具体呈现依赖于 HomeProduct 组件自身的实现。
 

5. 自定义文本样式扩展函数
@Extend(Text)function listItem(){.width(60).height(60).backgroundColor('#0966b4').fontFamily('myFont').fontSize(35).fontColor('#fff').borderRadius(30).textAlign(TextAlign.Center)
}
@Extend(Text)function icoText(){.fontSize(15).height(30).fontWeight('bolder')
}

通过 @Extend(Text) 装饰器为 Text 组件扩展了两个自定义样式函数。

  • listItem 函数主要用于给 Text 组件设置特定的宽高、背景颜色(使用之前注册的 myFont 字体、较大字体、白色字体颜色、圆形边框以及文本居中对齐等样式,从代码使用场景来看,可能用于那些作为图标样式展示的 Text 组件)。
  • icoText 函数则是给 Text 组件设置相对小一点的字体大小、固定高度以及加粗字体样式,用于那些配合图标展示的文字说明部分,使整体界面文字显示更规范统一且美观。

三、HomePruduct.ets文件中定义 HomeProduct 组件,展示商城主页中的内容。

实现代码如下:

interface  Data{src:ResourceStrtxt:stringprice:number
}
@Component
export default struct HomeProduct{@State datas: Data[] = []@State template: string = '1fr 1fr'aboutToAppear(): void {for(let i=1;i<=20;i++){this.datas.push({src:i%2==0? $r('app.media.product7'):$r('app.media.product1'),txt:'陶瓷产品'+i,price:15})}}@BuildergetItem(src:ResourceStr,txt:string,price:number){Column(){Image(src).width('100%').borderRadius(5)Text(txt).fontSize(15).fontWeight(FontWeight.Bold).margin({top:10})Text(){Span('¥ ').fontColor(Color.Red).fontSize(10)Span(price?.toFixed(2)).fontColor(Color.Red).fontWeight(FontWeight.Bold)}}.width('100%')}build() {Stack(){Column(){WaterFlow(){ForEach(this.datas,(item:Data)=>{FlowItem(){this.getItem(item.src,item.txt,item.price)}},(item:Data)=>JSON.stringify(item))}.columnsTemplate(this.template).rowsGap(10).columnsGap(10).nestedScroll({scrollForward: NestedScrollMode.PARENT_FIRST,scrollBackward:NestedScrollMode.SELF_FIRST})}.height('100%').width('100%')}.width('100%').height('100%').padding(5).alignContent(Alignment.Bottom)}
}

该组件用于展示一系列产品相关的信息,包括产品图片、名称以及价格等内容。组件内部实现了数据初始化、单个产品项的构建以及整体产品列表的布局展示等功能。
 

1. 接口定义
interface Data{src:ResourceStrtxt:stringprice:number
}

定义了一个名为 Data 的接口,用于规范表示产品数据的结构。其中包含三个属性:

 
  • src:类型为 ResourceStr,推测是用于引用资源(可能是图片资源等)的一种特定类型,用于指定产品对应的图片资源。
  • txt:字符串类型,用于存放产品的文字描述,比如产品名称等相关信息。
  • price:数值类型,用于表示产品的价格信息。

2.HomeProduct 组件定义
@Component
export default struct HomeProduct{//...
}
使用  @Component 装饰器将  HomeProduct 结构体标记为一个组件,意味着它可作为独立的 UI 单元参与界面构建,其界面呈现由内部的  build 方法来定义,同时还有相关的状态管理和生命周期方法等。

 
3. 组件状态定义
@State datas: Data[] = []
@State template: string = '1fr 1fr'
  • @State 装饰器用于定义组件的响应式状态变量。
  • datas:是一个 Data 类型的数组,初始化为空数组,用于存储要展示的多个产品的数据信息,后续会在组件的生命周期方法中进行数据填充。
  • template:是一个字符串类型的状态变量,初始值为 '1fr 1fr',从后续使用情况看,可能用于控制产品列表布局中列的模板(比如在 WaterFlow 布局里控制列的分布比例等情况)。
     
4.aboutToAppear 生命周期方法
aboutToAppear(): void {for(let i=1;i<=20;i++){this.datas.push({src:i%2==0? $r('app.media.product7'):$r('app.media.product1'),txt:'陶瓷产品'+i,price:15})}
}

aboutToAppear 方法通常在组件即将显示在界面上时被触发(是组件生命周期的一部分)。

  • 在这个方法中,通过一个循环(从 1 到 20)往 datas 数组中添加模拟的产品数据。对于每个产品:
    • src 属性根据索引 i 的奇偶性来选择不同的图片资源(通过 $r('app.media.productX') 方式引用,具体资源加载机制依赖框架实现),这里简单地实现了交替使用两种图片资源来模拟不同产品的图片。
    • txt 属性设置为 '陶瓷产品' 加上当前的索引值,形成一个简单的产品名称描述。
    • price 属性统一设置为 15,模拟产品价格。

5.getItem 构建函数
@Builder
getItem(src:ResourceStr,txt:string,price:number){Column(){Image(src).width('100%').borderRadius(5)Text(txt).fontSize(15).fontWeight(FontWeight.Bold).margin({top:10})Text(){Span('¥ ').fontColor(Color.Red).fontSize(10)Span(price?.toFixed(2)).fontColor(Color.Red).fontWeight(FontWeight.Bold)}}.width('100%')
}

使用 @Builder 装饰器,表明这是一个用于构建 UI 片段的函数,它接收产品的相关数据(图片资源、名称、价格)作为参数来构建一个产品项的 UI 结构。

  • 内部通过 Column(列布局)来组织产品项的内容:
    • 首先是一个 Image 组件,使用传入的 src 参数来显示产品图片,设置宽度占满父容器并且添加了圆角样式(borderRadius(5)),使其显示更美观。
    • 接着是一个 Text 组件,用于显示产品的名称(传入的 txt 参数),设置了字体大小为 15,加粗字体(FontWeight.Bold)以及顶部有一定的外边距,使其与图片有间隔。
    • 然后又是一个 Text 组件,内部使用了 Span 来分别构建价格显示的两部分(货币符号和具体价格数值),货币符号部分设置了红色字体颜色、较小的字体大小,价格数值部分同样设置为红色字体颜色并且加粗字体,整体用于清晰美观地展示产品价格信息,并且整个列布局宽度占满父容器。

6.build 方法(核心界面构建逻辑)
build() {Stack(){Column(){WaterFlow(){ForEach(this.datas,(item:Data)=>{FlowItem(){this.getItem(item.src,item.txt,item.price)}},(item:Data)=>JSON.stringify(item))}.columnsTemplate(this.template).rowsGap(10).columnsGap(10).nestedScroll({scrollForward: NestedScrollMode.PARENT_FIRST,scrollBackward:NestedScrollMode.SELF_FIRST})}.height('100%').width('100%')}.width('100%').height('100%').padding(5).alignContent(Alignment.Bottom)
}
 

整个界面构建基于 Stack(层叠布局),里面包含一个 Column(列布局),用于组织产品列表等内容。

  • Column 内部使用了 WaterFlow(瀑布流布局)组件来展示产品列表:
    • 通过 ForEach 循环遍历 datas 数组中的每个产品数据项(Data 类型),对于每个数据项,在 FlowItem 中调用 getItem 函数来构建对应的产品项 UI 结构,从而实现根据数据动态生成多个产品展示项的效果。同时传递了一个用于唯一标识每个数据项的函数(这里简单地将数据项转换为 JSON 字符串来作为标识)。
    • WaterFlow 组件设置了 columnsTemplate 为 this.template,即根据前面定义的 template 状态变量来确定列的布局模板(比如列的宽度分配比例等情况),设置了行与列之间的间隔(rowsGap(10) 和 columnsGap(10)),并且配置了嵌套滚动相关的模式(nestedScroll),用于处理滚动行为,比如规定了向前滚动(scrollForward)和向后滚动(scrollBackward)时采用的滚动模式(分别是 PARENT_FIRST 和 SELF_FIRST,涉及到和父容器滚动交互等情况)。
  • 外层的 Column 设置了高度和宽度占满父容器,而最外层的 Stack 同样设置了宽度和高度占满父容器,并且添加了一定的内边距(padding(5))以及内容对齐方式为底部对齐(alignContent(Alignment.Bottom)),整体构建出产品列表展示的完整界面布局结构。

四、在src/main/ets/pages/Index.ets文件中,定义Index 组件作为应用的入口组件。

实现代码如下:

import font from '@ohos.font'
import Home from "../components/Home"
@Entry
@Component
struct Index {aboutToAppear(): void {font.registerFont({familyName: 'myFont',familySrc: '/fonts/iconfont.ttf'})}@State selectedIndex: number = 0@BuildermyBuilder(itemIndex: number, title: string, ico: string) {Column() {Text(ico).width(30).height(30).fontFamily('myFont').fontSize(30).textAlign(TextAlign.Center).fontColor(itemIndex == this.selectedIndex ?'#fa2a83' : Color.Black)Text(title).fontColor(itemIndex == this.selectedIndex ? '#fa2a83' : Color.Black)}}build() {Tabs({ barPosition: BarPosition.End }) {TabContent() {Home()}.tabBar(this.myBuilder(0, '首页', '\ue64c'))TabContent() {Text("分类内容")}.tabBar(this.myBuilder(1, '分类', '\ue626'))TabContent() {Text("购物内容")}.tabBar(this.myBuilder(2, '购物', '\ue604'))TabContent() {Text("我的内容")}.tabBar(this.myBuilder(3, '我的', '\ue61e'))}.onChange((index: number) => {this.selectedIndex = index})}
}

定义了一个名为 Index 的组件,它作为应用的入口组件(通过 @Entry 装饰器标识),构建了一个带有底部导航栏(通过 Tabs 组件实现)的界面结构,导航栏包含多个选项卡,点击不同选项卡可切换显示不同的内容页面,同时在切换时还实现了相应的状态更新及样式变化等功能。

1. 导入模块
import font from '@ohos.font'
import Home from "../components/Home"

        从 @ohos.font 导入了 font 模块,大概率用于字体相关操作,后续代码中会使用它来注册自定义字体,以满足界面中特定字体显示需求。

        导入了自定义的 Home 组件,从代码结构推测,Home 组件应该是展示应用首页相关内容的一个独立组件,这里会被整合到 Tabs 所构建的多页面切换体系当中。

2.Index 组件定义与入口标识
@Entry
@Component
struct Index {//...
}
        使用  @Entry 装饰器将  Index 结构体标记为整个应用的入口组件,意味着应用启动时会首先渲染这个组件所定义的界面内容。同时, @Component 装饰器表明它是一个符合组件规范的 UI 单元,其界面呈现由内部的  build 方法来确定。

3.aboutToAppear 生命周期方法
aboutToAppear(): void {font.registerFont({familyName: 'myFont',familySrc: '/fonts/iconfont.ttf'})
}

        这是组件生命周期中在即将显示时触发的方法。在这里调用了 font 模块的 registerFont 方法,注册了一个名为 myFont 的自定义字体,字体文件来源指定为 /fonts/iconfont.ttf。注册这个字体后,后续就可以在界面中使用该字体来展示特定的文本样式了,例如显示一些自定义的图标字体等内容。

4. 组件状态定义
@State selectedIndex: number = 0
        通过  @State 装饰器定义了一个名为  selectedIndex 的响应式状态变量,其初始值设置为  0。这个变量用于记录当前选中的选项卡索引,在后续选项卡切换以及相应 UI 样式更新时会起到关键作用,因为界面上需要根据当前选中的选项卡来展示不同的样式效果,比如改变图标和文字的颜色等。

5.myBuilder 构建函数
@Builder
myBuilder(itemIndex: number, title: string, ico: string) {Column() {Text(ico).width(30).height(30).fontFamily('myFont').fontSize(30).textAlign(TextAlign.Center).fontColor(itemIndex == this.selectedIndex?'#fa2a83' : Color.Black)Text(title).fontColor(itemIndex == this.selectedIndex? '#fa2a83' : Color.Black)}
}

        使用 @Builder 装饰器表明这是一个用于构建 UI 片段的函数。

        该函数接收三个参数:

  • itemIndex(表示当前选项卡的索引)
  • title(选项卡对应的标题文本)
  • ico(用于显示的图标对应的字符编码,通常结合自定义字体来显示图标样式),并基于这些参数构建一个包含图标和标题文本的 Column(列布局)UI 结构。

        对于图标对应的 Text 组件:

        设置了固定的宽度和高度(width(30) 和 height(30)),指定使用之前注册的 myFont 字体,字体大小为 30,文本居中对齐(textAlign(TextAlign.Center)),并且关键的是,根据当前选项卡索引(itemIndex)与记录选中索引的 selectedIndex 是否相等,来动态设置字体颜色,如果相等则显示为 #fa2a83 颜色(可能是一种突出显示的颜色,用于标识选中状态),否则显示为黑色(普通未选中状态的颜色)。

        对于标题文本对应的 Text 组件,同样根据索引是否相等来动态设置字体颜色,以实现选中和未选中状态下文字颜色的不同显示效果,整体通过这个函数构建出每个选项卡对应的底部导航栏子项的展示样式。

6.build 方法(核心界面构建逻辑)
build() {Tabs({ barPosition: BarPosition.End }) {TabContent() {Home()}.tabBar(this.myBuilder(0, '首页', '\ue64c'))TabContent() {Text("分类内容")}.tabBar(this.myBuilder(1, '分类', '\ue626'))TabContent() {Text("购物内容")}.tabBar(this.myBuilder(2, '购物', '\ue604'))TabContent() {Text("我的内容")}.tabBar(this.myBuilder(3, '我的', '\ue61e'))}
.onChange((index: number) => {this.selectedIndex = index})
}

   整个界面构建基于 Tabs 组件,用于创建多选项卡切换的布局效果,并且通过 { barPosition: BarPosition.End } 参数设置选项卡栏的位置为底部(BarPosition.End 表示底部位置,还有其他可能的位置选项如顶部等)。

        在 Tabs 组件内部,有多个 TabContent 子组件,每个 TabContent 对应一个选项卡的内容页面:

  • 第一个 TabContent 中放置了之前导入的 Home 组件,作为应用的首页内容展示,并且通过 .tabBar(this.myBuilder(0, '首页', '\ue64c')) 调用 myBuilder 函数来构建对应的底部导航栏子项样式,传入索引 0、标题 '首页' 以及对应的图标字符编码 '\ue64c',用于显示首页对应的图标和文字样式,并且能根据选中状态改变颜色。
  • 后续的几个 TabContent 结构类似,分别展示简单的文本内容(如 '分类内容''购物内容''我的内容' 等),同样通过调用 myBuilder 函数传入不同的参数来构建各自对应的底部导航栏子项样式,每个选项卡都有自己对应的图标和文字,以及相应的选中 / 未选中状态样式变化。
  • 最后,通过 .onChange((index: number) => { this.selectedIndex = index }) 为 Tabs 组件注册了一个选项卡切换的回调函数,当用户点击切换选项卡时,会触发这个回调,将当前选中的选项卡索引更新到 selectedIndex 这个状态变量中,这样就能实时根据选中情况更新界面上相关元素(如底部导航栏图标和文字颜色)的样式了,保证 UI 展示与用户操作的一致性。

👋实验小结

本次实验成功构建了具有首页及底部导航栏多页面切换功能的应用界面。首页包含搜索栏、轮播图、分类网格与推荐好物列表等丰富内容,底部导航栏切换流畅且能实现选中状态样式更新。在技术层面,深入理解并运用组件化开发提升代码可维护性与复用性,像 Home 和 HomeProduct 组件各司其职;通过 @ohos.font 模块注册自定义字体用于图标展示,增强界面特色;灵活采用多种布局组件构建复杂结构,如 Column、Row 等布局的巧妙嵌套;借助响应式状态变量与数据循环达成数据驱动 UI,确保数据与界面显示一致。实验中遇到字体资源加载、布局适配及数据与 UI 同步等问题,均通过仔细检查路径、优化布局属性设置及遵循响应式编程最佳实践得以解决。此次实验收获颇丰,不仅熟练掌握组件化、布局构建与数据驱动等关键技术,还提升了问题解决能力,为后续应用开发积累了宝贵经验。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

unity学习8:unity的基础操作 和对应shortcut

目录 1 unity的基础操作的工具&#xff0c;就在scene边上 1.1 对应shortcut快捷键 2 物体的重置/ 坐标归到0附近 3 F&#xff1a;快速找到当前gameobject 4 Q&#xff1a;小手和眼睛&#xff0c;在场景中移动 5 W&#xff1a;十字箭头&#xff0c;移动gameobject 6 …

Harmony开发【笔记1】报错解决(字段名写错了。。)

在利用axios从网络接收请求时&#xff0c;发现返回obj的code为“-1”&#xff0c;非常不解&#xff0c;利用console.log测试&#xff0c;更加不解&#xff0c;可知抛出错误是 “ E 其他错误: userName required”。但是我在测试时&#xff0c;它并没有体现为空&#xff0c;…

(leetcode算法题)面试题 17.19. 消失的两个数字

可以在O(n)的时间复杂度下得到这两个消失的数字的异或的结果&#xff0c;或者得到这两个数字的和 但是怎么从上面的结果中得到这两个数字&#xff1f; 比如对于异或的结果&#xff0c;可以知道这两个数字在哪一位的置位是不同的 然后再根据这一位把 [1, n] 分为两个不同的数…

Go Ebiten随机迷宫生成示例

引言 迷宫生成是计算机科学中一个经典的问题&#xff0c;常用于算法教学和游戏开发。本文将介绍如何使用 Go 语言和 Ebiten 游戏引擎实现一个基于深度优先搜索&#xff08;DFS&#xff09;的随机迷宫生成算法&#xff0c;并通过可视化的方式展示迷宫的生成过程。 技术栈 Go …

Flutter 鸿蒙化 flutter和鸿蒙next混和渲染

前言导读 这一个节课我们讲一下PlatformView的是使用 我们在实战中有可能出现了在鸿蒙next只加载一部分Flutter的情况 我们今天就讲一下这种情况具体实现要使用到我们的PlatformView 效果图 具体实现: 一、Native侧 使用 DevEco Studio工具打开 platform_view_example\oho…

《一文读懂PyTorch核心模块:开启深度学习之旅》

《一文读懂PyTorch核心模块&#xff1a;开启深度学习之旅》 一、PyTorch 入门&#xff1a;深度学习的得力助手二、核心模块概览&#xff1a;构建深度学习大厦的基石三、torch&#xff1a;基础功能担当&#xff08;一&#xff09;张量操作&#xff1a;多维数组的神奇变换&#x…

jenkins入门6 --拉取代码

Jenkins代码拉取 需要的插件&#xff0c;缺少的安装下 新建一个item,选择freestyle project 源码管理配置如下&#xff1a;需要添加git库地址&#xff0c;和登录git的用户密码 配置好后执行编译&#xff0c;成功后拉取的代码在工作空间里

【2025最新计算机毕业设计】基于SpringBoot+Vue智慧养老医护系统(高质量源码,提供文档,免费部署到本地)【提供源码+答辩PPT+文档+项目部署】

作者简介&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容&#xff1a;&#x1f31f;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…

51c自动驾驶~合集45

我自己的原文哦~ https://blog.51cto.com/whaosoft/13020031 #运动控制和规划控制需要掌握的技术栈~ 各大垃圾家电造车厂又要开始了~~~​ 1、ROS的通信方式 李是Lyapunov的李&#xff1a;谈谈ROS的通信机制 话题通信和服务通信&#xff0c;其中话题通信是通过发布和订阅…

【Qt】控件概述和QWidget核心属性1(enabled、geometry、windowTitle、windowIcon、QRC机制)

一、控件概念 界面上各种元素、各种部分的统称&#xff08;如按钮、输入框、下拉框、单选复选框...&#xff09; Qt作为GUI开发框架&#xff0c;内置了各种的常用控件&#xff0c;并支持自定义控件。 二、控件体系发展 1.没有完全的控件&#xff0c;需要使用绘图API手动绘制…

基于transformer的目标检测:DETR

目录 一、背景介绍 二、DETR的工作流程 三、DETR的架构 1. 损失函数 2. 网络框架讲解及举例 一、背景介绍 在深度学习和计算机视觉领域&#xff0c;目标检测一直是一个核心问题。传统方法依赖于复杂的流程和手工设计的组件&#xff0c;如非极大值抑制&#xff08;nms&…

打包部署若依(RuoYi)SpringBoot后端和Vue前端图文教程

打包后端‘ 1&#xff0c;打开若依&#xff0c;点击右侧的Maven展开Maven管理&#xff0c;选择ruoyi>Lifecycle 先双击clean清除原本启动项目时生成的文件。然后点击package等待项目打包&#xff0c;切记要取消运行再打包 打包完成后会在ruoyi-admin>src>target里面…

RedisTemplate执行lua脚本及Lua 脚本语言详解

使用RedisTemplate执行lua脚本 在开发中&#xff0c;我们经常需要与Redis数据库进行交互&#xff0c;而Redis是一个基于内存的高性能键值存储数据库&#xff0c;它支持多种数据结构&#xff0c;并提供了丰富的命令接口。在某些情况下&#xff0c;我们可能需要执行一些复杂的逻…

倾斜摄影相机在不动产确权登记和权籍调查中的应用

一、项目背景 1.1 项目背景 为贯彻落实中央、国务院关于实施乡村振兴战略、关于“扎实推进房地一体的农村集体建设用地和宅基地使用权确权登记颁证&#xff0c;完善农民闲置宅基地和闲置农房政策&#xff0c;探索宅基地所有权、资格权、使用权‘三权分置’”的要求&#xff0…

SSL,TLS协议分析

写在前面 工作中总是会接触到https协议&#xff0c;也知道其使用了ssl&#xff0c;tls协议。但对其细节并不是十分的清楚。所以&#xff0c;就希望通过这篇文章让自己和读者朋友们都能对这方面知识有更清晰的理解。 1&#xff1a;tls/ssl协议的工作原理 1.1&#xff1a;设计的…

STM32 I2C通信外设

单片机学习&#xff01; 目录 前言 一、I2C外设简介 1.1 硬件I2C外设 1.2 硬件I2C功能 1.2.1 多主机模型 1.2.2 7位地址和10位地址的模式 1.2.3 通讯速度 1.2.4 支持DMA 1.2.5 兼容SMBus协议 1.2.6 芯片型号资源 二、I2C框图 2.1 引脚 2.2 SDA数据控制 2.3 SCL时…

新型大数据架构之湖仓一体(Lakehouse)架构特性说明——Lakehouse 架构(一)

文章目录 为什么需要新的数据架构&#xff1f;湖仓一体&#xff08;Lakehouse&#xff09;——新的大数据架构模式 同时具备数仓与数据湖的优点湖仓一体架构 存储层计算层 湖仓一体特性 单一存储拥有数据仓库的查询性能存算分离开放式架构支持各种数据源类型支持各种使用方式架…

Linux安全防火墙(iptables)配置策略

目录 概念 防火墙的主要功能和特点&#xff1a; 防火墙分类 其他概念 通信五要素&#xff1a; 通信四要素 用户态和内核态 四个表五个链 四个表 五条链 数据包过滤的匹配流程 三种报文流向&#xff1a; 规则内的匹配顺序&#xff1a; iptables iptables命令的格…

十四、Vue 混入(Mixins)详解

文章目录 简介一、基本语法定义混入对象使用混入对象二、混入的数据合并数据合并规则深度合并(对象类型数据)三、混入的生命周期钩子生命周期钩子的合并规则利用生命周期钩子合并的优势四、混入的方法合并方法合并规则调用被覆盖的方法(高级用法)五、混入的应用场景多个组件…

每日AIGC最新进展(80): 重庆大学提出多角色视频生成方法、Adobe提出大视角变化下的人类视频生成、字节跳动提出快速虚拟头像生成方法

Diffusion Models专栏文章汇总:入门与实战 Follow-Your-MultiPose: Tuning-Free Multi-Character Text-to-Video Generation via Pose Guidance 在多角色视频生成的研究中,如何实现文本可编辑和姿态可控的角色生成一直是一个具有挑战性的课题。现有的方法往往只关注单一对象的…