【HarmonyOS应用开发——ArkTS语言】购物商城的实现【合集】
目录
😋环境配置:华为HarmonyOS开发者
📺演示效果:
📖实验步骤及方法:
1. 在src/main/ets文件中创建components文件夹并在其中创建Home.ets和HomeProduct.ets文件。
2. 在Home.ets文件中定义 Home 组件,进行商城主页的布局与相关功能的部署。
导入模块
Home 组件定义
aboutToAppear 方法
build 方法(核心界面构建逻辑)
(1)整体布局结构:
(2)搜索栏部分:
(3)主体内容部分(基于 List 组件)
自定义文本样式扩展函数
3. 在HomePruduct.ets文件中定义 HomeProduct 组件,展示商城主页中的内容。
接口定义
HomeProduct 组件定义
组件状态定义
aboutToAppear 生命周期方法
getItem 构建函数
build 方法(核心界面构建逻辑)
4. 在src/main/ets/pages/Index.ets文件中,定义Index 组件作为应用的入口组件。
导入模块
Index 组件定义与入口标识
aboutToAppear 生命周期方法
组件状态定义
myBuilder 构建函数
build 方法(核心界面构建逻辑)
👋实验小结
😋环境配置:华为HarmonyOS开发者
🎯学习小目标:实现如下的购物商城主页效果
📺演示效果:
📖实验步骤及方法:
1. 在src/main/ets文件中创建components文件夹并在其中创建Home.ets和HomeProduct.ets文件。
2. 在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') }
该组件构建了一个具有特定布局和功能的界面,包含了搜索栏、轮播图、网格布局展示分类以及推荐好物相关展示等内容。
导入模块
import font from '@ohos.font'; import HomeProduct from '../components/HomeProduct';
从
@ohos.font
导入了font
模块,可能用于字体相关的操作,比如注册自定义字体等,从后续代码中对字体注册的使用可以印证这一点。导入了自定义的
HomeProduct
组件,推测这个组件用于展示具体的推荐好物等相关内容,不过代码中未给出HomeProduct
的具体实现细节。
Home
组件定义使用 @Component 装饰器将 Home 结构体标记为一个组件,意味着它可以在界面构建中被当作一个独立的 UI 单元来使用,并且按照其内部定义的 build 方法来渲染具体的界面内容。import font from '@ohos.font'; import HomeProduct from '../components/HomeProduct';
aboutToAppear
方法aboutToAppear(): void {font.registerFont({familyName: 'myFont',familySrc: '/fonts/iconfont.ttf'}) }
这是一个生命周期相关的方法,在组件即将显示时被调用(根据名称和常见的组件生命周期逻辑推测)。
它调用了
font
模块的registerFont
方法,目的是注册一个名为myFont
的自定义字体,字体文件来源指定为/fonts/iconfont.ttf
,这样后续就可以在组件中使用这个自定义字体来显示特定的文本样式了。
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
组件自身的实现。
自定义文本样式扩展函数
@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
组件设置相对小一点的字体大小、固定高度以及加粗字体样式,用于那些配合图标展示的文字说明部分,使整体界面文字显示更规范统一且美观。
3. 在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)} }
该组件用于展示一系列产品相关的信息,包括产品图片、名称以及价格等内容。组件内部实现了数据初始化、单个产品项的构建以及整体产品列表的布局展示等功能。
接口定义
interface Data{src:ResourceStrtxt:stringprice:number }
定义了一个名为
Data
的接口,用于规范表示产品数据的结构。其中包含三个属性:
src
:类型为ResourceStr
,推测是用于引用资源(可能是图片资源等)的一种特定类型,用于指定产品对应的图片资源。txt
:字符串类型,用于存放产品的文字描述,比如产品名称等相关信息。price
:数值类型,用于表示产品的价格信息。
HomeProduct
组件定义使用@Component export default struct HomeProduct{//... }
@Component
装饰器将HomeProduct
结构体标记为一个组件,意味着它可作为独立的 UI 单元参与界面构建,其界面呈现由内部的build
方法来定义,同时还有相关的状态管理和生命周期方法等。
组件状态定义
@State datas: Data[] = [] @State template: string = '1fr 1fr'
@State
装饰器用于定义组件的响应式状态变量。datas
:是一个Data
类型的数组,初始化为空数组,用于存储要展示的多个产品的数据信息,后续会在组件的生命周期方法中进行数据填充。template
:是一个字符串类型的状态变量,初始值为'1fr 1fr'
,从后续使用情况看,可能用于控制产品列表布局中列的模板(比如在WaterFlow
布局里控制列的分布比例等情况)。
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
,模拟产品价格。
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
来分别构建价格显示的两部分(货币符号和具体价格数值),货币符号部分设置了红色字体颜色、较小的字体大小,价格数值部分同样设置为红色字体颜色并且加粗字体,整体用于清晰美观地展示产品价格信息,并且整个列布局宽度占满父容器。
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)
),整体构建出产品列表展示的完整界面布局结构。
4. 在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
组件实现)的界面结构,导航栏包含多个选项卡,点击不同选项卡可切换显示不同的内容页面,同时在切换时还实现了相应的状态更新及样式变化等功能。
导入模块
import font from '@ohos.font' import Home from "../components/Home"
从
@ohos.font
导入了font
模块,大概率用于字体相关操作,后续代码中会使用它来注册自定义字体,以满足界面中特定字体显示需求。导入了自定义的
Home
组件,从代码结构推测,Home
组件应该是展示应用首页相关内容的一个独立组件,这里会被整合到Tabs
所构建的多页面切换体系当中。
Index
组件定义与入口标识使用@Entry @Component struct Index {//... }
@Entry
装饰器将Index
结构体标记为整个应用的入口组件,意味着应用启动时会首先渲染这个组件所定义的界面内容。同时,@Component
装饰器表明它是一个符合组件规范的 UI 单元,其界面呈现由内部的build
方法来确定。
aboutToAppear
生命周期方法aboutToAppear(): void {font.registerFont({familyName: 'myFont',familySrc: '/fonts/iconfont.ttf'}) }
这是组件生命周期中在即将显示时触发的方法。在这里调用了
font
模块的registerFont
方法,注册了一个名为myFont
的自定义字体,字体文件来源指定为/fonts/iconfont.ttf
。注册这个字体后,后续就可以在界面中使用该字体来展示特定的文本样式了,例如显示一些自定义的图标字体等内容。
组件状态定义
通过@State selectedIndex: number = 0
@State
装饰器定义了一个名为selectedIndex
的响应式状态变量,其初始值设置为0
。这个变量用于记录当前选中的选项卡索引,在后续选项卡切换以及相应 UI 样式更新时会起到关键作用,因为界面上需要根据当前选中的选项卡来展示不同的样式效果,比如改变图标和文字的颜色等。
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
组件,同样根据索引是否相等来动态设置字体颜色,以实现选中和未选中状态下文字颜色的不同显示效果,整体通过这个函数构建出每个选项卡对应的底部导航栏子项的展示样式。
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 同步等问题,均通过仔细检查路径、优化布局属性设置及遵循响应式编程最佳实践得以解决。此次实验收获颇丰,不仅熟练掌握组件化、布局构建与数据驱动等关键技术,还提升了问题解决能力,为后续应用开发积累了宝贵经验。
相关文章:

【HarmonyOS应用开发——ArkTS语言】购物商城的实现【合集】
目录 😋环境配置:华为HarmonyOS开发者 📺演示效果: 📖实验步骤及方法: 1. 在src/main/ets文件中创建components文件夹并在其中创建Home.ets和HomeProduct.ets文件。 2. 在Home.ets文件中定义 Home 组…...
Python二维码生成器qrcode库
要在Python中生成二维码,你可以使用 qrcode 库。这个库非常方便,允许你生成并保存二维码图像。下面是一个简单的示例,展示了如何使用 qrcode 库生成二维码。 首先,你需要安装 qrcode 库。你可以使用 pip 来安装它: s…...

Python:模拟(包含例题:饮料换购 图像模糊 螺旋矩阵)
模拟题:直接按照题目含义模拟即可,一般不涉及算法 注意: 1.读懂题:理清楚题目流程 2.代码和步骤一一对应:变量名,函数名,函数功能 3.提取重复的部分,写成对应的函数(…...
git分支与部署环境的关系以及开发规范
一 某金融机构 1.1 分支分类以及作用 1.master master分支为主分支,用于部署生产环境的分支,无论任何时候都要确保master分支的稳定性;master分支由feature及hotfix分支合并,任何时间都不能直接修改代码。目前用于老仿真和老生产,暂时不动。 2.prod 主分支,是master…...
2024最新鸿蒙开发面试题合集(一)-HarmonyOS NEXT Release(API 12 Release)
1. HarmonyOS应用打包后的文件扩展名是? 打包后的文件扩展名为.hap(HarmonyOS Ability Package),这是HarmonyOS应用的标准包格式 2. 页面和自定义组件生命周期有哪些? 页面和自定义组件生命周期说明 有Entry装饰器的component组件的生命…...
【mybatis】详解 # 和 $ 的区别,两者分别适用于哪种场景,使用 $ 不当会造成什么影响
# 和 $ 的区别 在MyBatis中,# 和 $ 是用来处理参数的两种不同方式,它们之间有一些重要的区别: # 符号: # 是用来进行参数占位符的,它会进行 SQL 注入防护。使用 # 时,MyBatis 会将参数值进行预处理&…...
Java面试题,数据结构,图的最短路径算法应用于社交网络分析
图的最短路径算法应用于社交网络分析 在一个大型社交网络中,用户想要找到连接两个特定用户的最短路径。假设你已经有了这个社交网络的数据模型,其中节点代表用户,边代表用户之间的关系。请设计一个解决方案,以找出两个用户之间的…...

Tree数据处理
文章目录 一、Tree数据重置二、Tree拆分成二级数据1、过滤数据2、二级数据 Tree组件的数据处理往往需要使用递归,本文归纳一下常见的数据处理情景,持续更新; 一、Tree数据重置 递归的标志就是寻找子元素的集合字段,一般为children…...

idea配置gitee仓库
idea配置gitee 0、fork开源项目 到自己的仓库,这一步相当于创建了一个自己的git仓库,并复制了别人的开源代码。 注意:如果直接下载别人的开源项目,需要从新配置git仓库信息,因为开源项目一般都设置了git信息。而修改…...

SpringBoot 事务
事务是一组操作的集合, 是一个不可分割的操作.会把所有的操作作为一个整体, 一起向数据库提交或者是撤销操作请求. 所以这组操作要么同时成功, 要么同时失败. 为什么需要事务? 我们在进行程序开发时, 也会有事务的需求. 比如转账操作: 第一步:A 账户 -100 元. …...

我的JAVA-Web基础(1)
1.HTML 2.css CSS(层叠样式表)提供了多种选择器来定位HTML文档中的元素,以便可以应用样式。以下是三种常用的选择器简述: ID 选择器: ID选择器使用HTML元素的id属性来定位单个元素。每个页面中id应该是唯一的…...
【Leetcode 热题 100】207. 课程表
问题背景 你这个学期必须选修 n u m C o u r s e s numCourses numCourses 门课程,记为 0 0 0 到 n u m C o u r s e s − 1 numCourses - 1 numCourses−1。 在选修某些课程之前需要一些先修课程。 先修课程按数组 p r e r e q u i s i t e s prerequisites p…...
从CreateDialogIndirectParam起---我与大模型对话
前言: 对当前的大模型来说,一切皆程序,皆标准。只能按照推定的线路行走,就像机器人走进死胡同,不停的踏步也不回头。除非人为去干预它。其实我提出的这个问题前是因为我不清楚了解一部分WinAPI有着严格的检查机制和自毁…...

重温设计模式--建造者模式
文章目录 建造者模式(Builder Pattern)概述建造者模式UML图作用:建造者模式的结构产品(Product):抽象建造者(Builder):具体建造者(Concrete Builderÿ…...
CSS(五):定位
目录 相对定位 绝对定位 固定定位 在 CSS 中,position 属性用于控制元素的定位方式,使我们可以精确地控制元素在页面上的位置。定位分为相对定位、绝对定位、和固定定位 相对定位 相对定位:position: relative; 相对定位意味着元素的位置…...
JSON 系列之2:JSON简单查询
本文为Oracle数据库JSON学习系列的第2篇,讲述如何对存储在数据库中的JSON文档进行简单的查询。 创建测试表,插入2条数据: DROP TABLE colortab PURGE;CREATE TABLE colortab (id NUMBER,color VARCHAR2(4000),CONSTRAINT ensure_json CH…...

SQL 简单查询
目录 一、投影查询 1、指定特定列查询 2、修改返回列名查询 3、计算值查询 二、选择查询 1、使用关系表达式 2、使用逻辑表达式 3、使用 BETWEEN关键字 4、使用 IN关键字 5、使用 LIKE关键字 6、使用 IS NULL/ NOT NULL关键字 7、符合条件查询 三、聚合函数查询 一…...
YOLOv9-0.1部分代码阅读笔记-metrics.py
metrics.py utils\metrics.py 目录 metrics.py 1.所需的库和模块 2.def fitness(x): 3.def smooth(y, f0.05): 4.def ap_per_class(tp, conf, pred_cls, target_cls, plotFalse, save_dir., names(), eps1e-16, prefix""): 5.def compute_ap(recall, prec…...
KaiOS 4.0 | DataCall and setupData implemention
相关文档 1、KaiOS 3.1 系统介绍 KaiOS 系统框架和应用结构(APP界面逻辑)文章浏览阅读842次,点赞17次,收藏5次。对于Java开发者而言,理解JS的逻辑调用是有点困难的。而KaiOS webapp开发又不同于现代的web开发,更像chrome浏览器内嵌模式。在这里梳理一下kaios平台web应用…...

nginx-rtmp服务器搭建
音视频服务器搭建 本文采用 nginx/1.18.0和nginx-rtmp-module模块源代码搭建RTMP流媒体服务器 流程 查看当前服务器的nginx版本下载nginx和nginx-rtmp-module源代码重新编译nginx,并进行相关配置(nginx.conf、防火墙等)客户端测试连接测试搭…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...

九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...

算法—栈系列
一:删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {stack<char> st;for(int i 0; i < s.size(); i){char target s[i];if(!st.empty() && target st.top())st.pop();elsest.push(s[i]);}string ret…...

qt+vs Generated File下的moc_和ui_文件丢失导致 error LNK2001
qt 5.9.7 vs2013 qt add-in 2.3.2 起因是添加一个新的控件类,直接把源文件拖进VS的项目里,然后VS卡住十秒,然后编译就报一堆 error LNK2001 一看项目的Generated Files下的moc_和ui_文件丢失了一部分,导致编译的时候找不到了。因…...

npm安装electron下载太慢,导致报错
npm安装electron下载太慢,导致报错 背景 想学习electron框架做个桌面应用,卡在了安装依赖(无语了)。。。一开始以为node版本或者npm版本太低问题,调整版本后还是报错。偶尔执行install命令后,可以开始下载…...