HarmonyOS 鸿蒙Next用MVVM思想封装自定义TabBar组件
HarmonyOS 鸿蒙Next用MVVM思想封装自定义TabBar组件
<markdown _ngcontent-dnp-c149="" class="markdownPreContainer">
介绍
在使用上次封装好的 Container组件 的基础上,使用MVVM思想封装一个自定义TabBar组件
效果图
代码
Index.ets
// Index.ets
import Container from '../components/Container/Container'
import TabBar from '../components/TabBar/TabBar'
@Entry
@Component
struct Index {
@Builder
headerBuilder() {
Text(‘header’)
}
@Builder
contentBuilder() {
Text(‘content’)
}
@Builder
tabBarBuilder() {
Row(){
TabBar()
}
}
build() {
Column() {
Container({
headerBuilderParam: this.headerBuilder,
contentBuilderParam: this.contentBuilder,
tabBarBuilderParam: this.tabBarBuilder,
// headerBackgroundColor: ‘#ccc’,
// contentBackgroundColor: ‘#ccc’,
tabBarBackgroundColor: ‘#eee’,
})
}
}
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
Container.ets
// Container.ets
[@Component](/user/Component)
export default struct Container {
[@BuilderParam](/user/BuilderParam) headerBuilderParam: () => void = this.headerBuilder
[@BuilderParam](/user/BuilderParam) contentBuilderParam: () => void = this.contentBuilder
[@BuilderParam](/user/BuilderParam) tabBarBuilderParam: () => void = this.tabBarBuilder
@Builder
headerBuilder() {
}
@Builder
contentBuilder() {
}
@Builder
tabBarBuilder() {
}
headerBackgroundColor: ResourceColor = Color.Red
contentBackgroundColor: ResourceColor = Color.Yellow
tabBarBackgroundColor: ResourceColor = Color.Green
headerHeight: Length = 44
tabBarHeight: Length = 50
build() {
Flex({ direction: FlexDirection.Column }) {
Row() {
this.headerBuilderParam()
}.width(‘100%’).backgroundColor(this.headerBackgroundColor).height(this.headerHeight)
Row() {
<span class="hljs-keyword">this</span>.contentBuilderParam()
}.width(<span class="hljs-string">'100%'</span>).backgroundColor(<span class="hljs-keyword">this</span>.contentBackgroundColor).flexGrow(<span class="hljs-number">1</span>)
Row() {
<span class="hljs-keyword">this</span>.tabBarBuilderParam()
}.width(<span class="hljs-string">'100%'</span>).backgroundColor(<span class="hljs-keyword">this</span>.tabBarBackgroundColor).height(<span class="hljs-keyword">this</span>.tabBarHeight)
}
}
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
TabBar.ets
// TabBar.ets
import TabBarItem from './TabBarItem'
import TabBarViewModel from './TabBarViewModel'
@Component
export default struct TabBar {
@State tabBarViewModel: TabBarViewModel = new TabBarViewModel([
new TabBarItem($rawfile(‘home-unselected.png’),$rawfile(‘home-selected.png’),‘主页’),
new TabBarItem($rawfile(‘category-unselected.png’),$rawfile(‘category-selected.png’),‘分类’),
new TabBarItem($rawfile(‘cart-unselected.png’),$rawfile(‘cart-selected.png’),‘购物车’),
new TabBarItem($rawfile(‘user-unselected.png’),$rawfile(‘user-selected.png’),‘用户’),
new TabBarItem($rawfile(‘test-unselected.png’),$rawfile(‘test-selected.png’),‘测试’),
])
build() {
Row(){
ForEach(this.tabBarViewModel.tabBarItems, (tabBarItem: TabBarItem, index: number)=>{
Column(){
Image(this.tabBarViewModel.selectedIndex !== index ?
tabBarItem.imageUrlUnselected : tabBarItem.imageUrlSelected
).width(30).height(30)
Text(tabBarItem.title)
.fontColor(this.tabBarViewModel.selectedIndex !== index?’#000’:’#f66’)
}.width(<span class="javascript">${<span class="hljs-number">100</span>/<span class="hljs-keyword">this</span>.tabBarViewModel.tabBarItems.length}%</span>
)
.onClick(()=>{
this.tabBarViewModel.selectedIndex = index
})
})</span>
}.<span class="hljs-title">width</span><span class="hljs-params">(<span class="hljs-string">'100%'</span>)</span>.<span class="hljs-title">height</span><span class="hljs-params">(<span class="hljs-string">'100%'</span>)</span>
}
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
TabBarItem.ets
// TabBarItem.ets
[@Observed](/user/Observed)
export default class TabBarItem{
imageUrlUnselected: Resource
imageUrlSelected: Resource
title: string
constructor(
imageUrlUnselected: Resource,
imageUrlSelected: Resource,
title: string,
) {
this.imageUrlUnselected = imageUrlUnselected
this.imageUrlSelected = imageUrlSelected
this.title = title
}
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
TabBarViewModel.ets
// TabBarViewModel.ets
import TabBarItem from './TabBarItem'
@Observed
export default class TabBarViewModel{
tabBarItems: TabBarItem[]
selectedIndex: number
constructor(
tabBarItems: TabBarItem[],
selectedIndex: number = 0,
) {
this.tabBarItems = tabBarItems
this.selectedIndex = selectedIndex
}
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
</markdown>
在HarmonyOS鸿蒙Next系统中,使用MVVM(Model-View-ViewModel)思想封装自定义TabBar组件,可以遵循以下原则:
-
Model层:定义TabBar的数据模型,包括每个Tab的图标、标题、选中状态等。
-
View层:使用HarmonyOS提供的UI组件(如CustomLayout或DirectionalLayout)来布局TabBar,通过数据绑定将Model层的数据展示到UI上。
-
ViewModel层:作为Model和View之间的桥梁,处理业务逻辑和状态管理。可以监听用户点击事件,更新Model层的数据,并通知View层刷新UI。
在封装过程中,需要注意以下几点:
- 确保TabBar的样式和交互符合产品要求。
- 处理好Tab切换时的动画效果,提升用户体验。
- ViewModel层应尽可能独立,减少与View层的直接依赖,便于单元测试和维护。
同时,利用HarmonyOS提供的组件化开发能力,可以将自定义TabBar组件封装成一个独立的模块,方便在多个项目中使用。
如果在实际开发过程中遇到具体的技术问题,如数据绑定失败、组件渲染异常等,可以查阅HarmonyOS的官方文档或开发者社区获取更多帮助。如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html。