152.[HarmonyOS NEXT 实战案例十二:List系列] 卡片样式列表组件实战:打造精美电商应用 进阶篇
[HarmonyOS NEXT 实战案例十二:List系列] 卡片样式列表组件实战:打造精美电商应用 进阶篇
项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star
效果演示
一、引言
在基础篇中,我们学习了如何使用HarmonyOS NEXT的Grid
组件实现一个基本的卡片样式商品列表。本篇教程将在此基础上,探索更多进阶特性和优化技巧,帮助你打造一个功能更加丰富、用户体验更加流畅的电商应用。
我们将重点关注以下几个方面:
- 卡片样式的高级定制
- 瀑布流布局实现
- 高级交互效果
- 列表加载与刷新
- 动画与过渡效果
- 高级筛选功能
二、卡片样式的高级定制
2.1 自定义卡片样式
在基础篇中,我们实现了基本的商品卡片样式。现在,我们可以进一步定制卡片样式,使其更加精美:
@Builder
EnhancedProductCard(product: ProductType) {
Column() {
// 商品图片区域
Stack() {
Image(product.image)
.width('100%')
.aspectRatio(1)
.objectFit(ImageFit.Cover)
.borderRadius({ topLeft: 8, topRight: 8 })
.overlay('rgba(0, 0, 0, 0.03)') // 添加轻微的遮罩
// 商品标签容器
Column() {
// 新品标签
if (product.isNew) {
Row() {
Image($r('app.media.ic_new'))
.width(16)
.height(16)
.margin({ right: 4 })
Text('新品')
.fontSize(12)
.fontColor('#FFFFFF')
}
.padding({ left: 8, right: 8, top: 4, bottom: 4 })
.backgroundColor('#FF5722')
.borderRadius({ topRight: 8, bottomRight: 8 })
.margin({ top: 8 })
}
// 热卖标签
if (product.isHot) {
Row() {
Image($r('app.media.ic_hot'))
.width(16)
.height(16)
.margin({ right: 4 })
Text('热卖')
.fontSize(12)
.fontColor('#FFFFFF')
}
.padding({ left: 8, right: 8, top: 4, bottom: 4 })
.backgroundColor('#FF9800')
.borderRadius({ topRight: 8, bottomRight: 8 })
.margin({ top: 8 })
}
}
.alignItems(HorizontalAlign.Start)
.position({ x: 0, y: 0 })
// 收藏按钮
Button({ type: ButtonType.Circle, stateEffect: true }) {
Image(product.isFavorite ? $r('app.media.ic_favorite_filled') : $r('app.media.ic_favorite'))
.width(20)
.height(20)
.fillColor(product.isFavorite ? '#FF5722' : '#FFFFFF')
}
.width(36)
.height(36)
.backgroundColor('rgba(255, 255, 255, 0.8)')
.position({ x: '100%', y: 0 })
.translate({ x: -44, y: 8 })
.onClick(() => {
// 切换收藏状态
product.isFavorite = !product.isFavorite;
})
}
.width('100%')
// 商品信息区域
Column() {
// 商品名称
Text(product.name)
.fontSize(14)
.fontColor('#333333')
.fontWeight(FontWeight.Medium)
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.width('100%')
// 价格和折扣信息
Row() {
Column() {
// 价格区域
Row() {
Text('¥')
.fontSize(12)
.fontColor('#FF5722')
.fontWeight(FontWeight.Bold)
Text(product.price.toFixed(2))
.fontSize(16)
.fontColor('#FF5722')
.fontWeight(FontWeight.Bold)
}
// 原价和折扣
Row() {
Text(`¥${product.originalPrice.toFixed(2)}`)
.fontSize(12)
.fontColor('#999999')
.decoration({ type: TextDecorationType.LineThrough })
Text(product.discount)
.fontSize(12)
.fontColor('#FF5722')
.backgroundColor('#FFF0E6')
.padding({ left: 4, right: 4, top: 1, bottom: 1 })
.borderRadius(2)
.margin({ left: 4 })
}
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
// 购物车按钮
Button({ type: ButtonType.Circle }) {
Image($r('app.media.ic_cart_add'))
.width(20)
.height(20)
.fillColor('#FFFFFF')
}
.width(32)
.height(32)
.backgroundColor('#FF5722')
.onClick(() => {
// 添加到购物车
this.addToCart(product);
})
}
.width('100%')
.margin({ top: 8 })
// 销量和评分
Row() {
Text(`${product.sales}人已购买`)
.fontSize(12)
.fontColor('#999999')
if (product.rating) {
Row() {
ForEach([1, 2, 3, 4, 5], (item) => {
Image($r('app.media.ic_star'))
.width(12)
.height(12)
.fillColor(item <= product.rating ? '#FFC107' : '#E0E0E0')
.margin({ right: item < 5 ? 2 : 0 })
})
}
.margin({ left: 8 })
}
}
.width('100%')
.margin({ top: 4 })
}
.width('100%')
.padding({ left: 12, right: 12, top: 12, bottom: 12 })
}
.width('100%')
.backgroundColor('#FFFFFF')
.borderRadius(8)
.shadow({
radius: 8,
color: 'rgba(0, 0, 0, 0.1)',
offsetX: 0,
offsetY: 2
})
.stateStyles({
pressed: {
transform: { scale: { x: 0.98, y: 0.98 } },
opacity: 0.9,
shadow: {
radius: 6,
color: 'rgba(0, 0, 0, 0.08)',
offsetX: 0,
offsetY: 1
}
},
normal: {
transform: { scale: { x: 1.0, y: 1.0 } },
opacity: 1.0,
shadow: {
radius: 8,
color: 'rgba(0, 0, 0, 0.1)',
offsetX: 0,
offsetY: 2
}
}
})
.onClick(() => {
// 点击商品卡片的处理逻辑
this.navigateToProductDetail(product);
})
}
这个增强版的商品卡片包含以下改进:
- 更精美的标签设计:新品和热卖标签添加了图标,使用了更美观的样式
- 收藏按钮:右上角添加了收藏按钮,用户可以直接收藏商品
- 购物车按钮:添加了快速加入购物车的按钮
- 评分展示:使用星星图标展示商品评分
- 更丰富的状态样式:点击时不仅有缩放效果,还有阴影变化
- 图片遮罩:添加轻微的遮罩,提升视觉效果
2.2 卡片样式主题化
为了支持不同的视觉主题(如日间/夜间模式),我们可以实现卡片样式的主题化:
// 定义主题颜色
class ThemeColors {
static readonly light = {
background: '#FFFFFF',
cardBackground: '#FFFFFF',
primaryText: '#333333',
secondaryText: '#999999',
accentColor: '#FF5722',
borderColor: '#E5E5E5',
shadowColor: 'rgba(0, 0, 0, 0.1)'
}
static readonly dark = {
background: '#121212',
cardBackground: '#1E1E1E',
primaryText: '#E0E0E0',
secondaryText: '#9E9E9E',
accentColor: '#FF7043',
borderColor: '#333333',
shadowColor: 'rgba(0, 0, 0, 0.2)'
}
}
// 使用AppStorage存储当前主题
AppStorage.SetOrCreate('themeMode', 'light');
// 在组件中使用主题颜色
@StorageLink('themeMode') themeMode: string = 'light';
get colors() {
return this.themeMode === 'light' ? ThemeColors.light : ThemeColors.dark;
}
// 在卡片样式中应用主题颜色
.backgroundColor(this.colors.cardBackground)
.shadow({
radius: 8,
color: this.colors.shadowColor,
offsetX: 0,
offsetY: 2
})
通过这种方式,我们可以轻松实现卡片样式的主题切换,适应不同的使用场景和用户偏好。
三、瀑布流布局实现
瀑布流布局是卡片样式列表的一种变体,它允许卡片具有不同的高度,更适合展示不规则内容。
3.1 使用WaterFlow组件
HarmonyOS NEXT提供了WaterFlow
组件,专门用于实现瀑布流布局:
WaterFlow() {
ForEach(this.productList, (product: ProductType) => {
FlowItem() {
this.EnhancedProductCard(product)
}
})
}
.columnsTemplate('1fr 1fr') // 两列布局
.itemConstraintSize({ // 设置项目尺寸约束
minWidth: 160,
maxWidth: '100%'
})
.columnsGap(8) // 列间距
.rowsGap(8) // 行间距
.padding(8) // 内边距
.layoutDirection(FlexDirection.Column) // 布局方向
.onReachStart(() => { // 到达顶部时触发
console.info('Reached start');
})
.onReachEnd(() => { // 到达底部时触发
this.loadMoreProducts();
})
WaterFlow
组件的主要特点:
- 使用
FlowItem
作为子组件,每个FlowItem
可以有不同的高度 - 支持
onReachStart
和onReachEnd
事件,方便实现下拉刷新和上拉加载更多 - 通过
itemConstraintSize
设置项目的尺寸约束
3.2 动态计算卡片高度
为了实现真正的瀑布流效果,我们需要根据内容动态计算卡片高度:
// 扩展商品数据类型,添加内容高度属性
type EnhancedProductType = ProductType & {
contentHeight?: number
}
// 预处理商品数据,计算内容高度
preprocessProducts() {
this.productList.forEach((product: EnhancedProductType) => {
// 基础高度
let baseHeight = 280;
// 根据名称长度调整高度
const nameLines = Math.ceil(product.name.length / 12); // 假设每行约12个字符
baseHeight += (nameLines - 1) * 20; // 每多一行增加20高度
// 根据是否有标签调整高度
if (product.isNew || product.isHot) {
baseHeight += 10;
}
// 根据是否有评分调整高度
if (product.rating) {
baseHeight += 20;
}
product.contentHeight = baseHeight;
});
}
// 在FlowItem中应用动态高度
FlowItem() {
this.EnhancedProductCard(product)
.height(product.contentHeight)
}
通过这种方式,我们可以根据商品内容的不同,动态计算卡片高度,实现真正的瀑布流效果。
四、高级交互效果
4.1 滑动操作
我们可以为商品卡片添加滑动操作,如收藏、加入购物车等:
@Builder
ProductCardWithSwipe(product: ProductType) {
SwipeAction() {
// 卡片内容
this.EnhancedProductCard(product)
// 滑动操作按钮
SwipeActionButton() {
Column() {
Image($r('app.media.ic_favorite'))
.width(24)
.height(24)
.fillColor('#FFFFFF')
Text('收藏')
.fontSize(12)
.fontColor('#FFFFFF')
.margin({ top: 4 })
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
.backgroundColor('#FF9800')
SwipeActionButton() {
Column() {
Image($r('app.media.ic_cart_add'))
.width(24)
.height(24)
.fillColor('#FFFFFF')
Text('加入购物车')
.fontSize(12)
.fontColor('#FFFFFF')
.margin({ top: 4 })
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
.backgroundColor('#FF5722')
}
.onSwipeActionButtonClick((index: number) => {
if (index === 0) {
// 收藏操作
product.isFavorite = !product.isFavorite;
} else if (index === 1) {
// 加入购物车操作
this.addToCart(product);
}
})
}
这段代码使用SwipeAction
组件实现滑动操作:
- 向左滑动可以显示"收藏"和"加入购物车"按钮
- 点击按钮时触发相应的操作
4.2 拖拽排序
我们可以实现拖拽排序功能,让用户自定义商品的显示顺序:
@State dragIndex: number = -1
Grid() {
ForEach(this.filteredProductList, (product: ProductType, index) => {
GridItem() {
this.EnhancedProductCard(product)
}
.draggable(true)
.opacity(this.dragIndex === index ? 0.6 : 1.0)
})
}
.onDragStart((event: DragEvent, itemIndex: number) => {
this.dragIndex = itemIndex;
return this.filteredProductList[itemIndex];
})
.onDrop((event: DragEvent, itemIndex: number) => {
// 交换位置
if (this.dragIndex !== itemIndex && this.dragIndex !== -1) {
const temp = this.filteredProductList[this.dragIndex];
this.filteredProductList[this.dragIndex] = this.filteredProductList[itemIndex];
this.filteredProductList[itemIndex] = temp;
}
this.dragIndex = -1;
})
.onDragEnd(() => {
this.dragIndex = -1;
})
这段代码实现了拖拽排序功能:
- 使用
draggable
属性使GridItem可拖拽 - 在拖拽过程中改变透明度提供视觉反馈
- 在拖拽结束时交换商品位置
五、列表加载与刷新
5.1 下拉刷新
我们可以为卡片列表添加下拉刷新功能:
Refresh({ refreshing: this.isRefreshing }) {
Column() {
// 分类和排序选项
this.CategoryTabs()
this.SortOptions()
// 商品列表
Grid() {
ForEach(this.filteredProductList, (product: ProductType) => {
GridItem() {
this.EnhancedProductCard(product)
}
})
}
.columnsTemplate('1fr 1fr')
.columnsGap(8)
.rowsGap(8)
.padding(8)
.layoutWeight(1)
}
.width('100%')
}
.onRefresh(() => {
// 模拟刷新数据
this.isRefreshing = true;
setTimeout(() => {
// 重新加载商品数据
this.loadProducts();
this.isRefreshing = false;
}, 2000);
})
这段代码使用Refresh
组件包裹内容区域,实现下拉刷新功能:
- 使用
isRefreshing
状态控制刷新状态 - 在
onRefresh
回调中重新加载商品数据
5.2 无限滚动加载
我们可以实现无限滚动加载功能,当用户滚动到列表底部时自动加载更多商品:
@State hasMoreProducts: boolean = true
@State isLoadingMore: boolean = false
@State currentPage: number = 1
// 在Grid组件底部添加加载更多指示器
Grid() {
// 商品列表项
ForEach(this.filteredProductList, (product: ProductType) => {
GridItem() {
this.EnhancedProductCard(product)
}
})
// 加载更多指示器
if (this.hasMoreProducts || this.isLoadingMore) {
GridItem() {
Column() {
if (this.isLoadingMore) {
LoadingProgress()
.width(24)
.height(24)
Text('正在加载更多...')
.fontSize(14)
.fontColor('#999999')
.margin({ top: 8 })
} else {
Text('上拉加载更多')
.fontSize(14)
.fontColor('#999999')
}
}
.width('100%')
.height(60)
.justifyContent(FlexAlign.Center)
}
.columnStart(0)
.columnEnd(1)
}
}
.onReachEnd(() => {
if (this.hasMoreProducts && !this.isLoadingMore) {
this.loadMoreProducts();
}
})
// 加载更多商品
loadMoreProducts() {
if (this.isLoadingMore) return;
this.isLoadingMore = true;
this.currentPage++;
// 模拟加载更多数据
setTimeout(() => {
// 假设每页加载10个商品
const newProducts = this.generateMoreProducts(10);
if (newProducts.length > 0) {
this.productList = this.productList.concat(newProducts);
this.filterProducts(); // 应用当前的过滤和排序
} else {
this.hasMoreProducts = false;
}
this.isLoadingMore = false;
}, 1500);
}
这段代码实现了无限滚动加载功能:
- 使用
onReachEnd
事件检测滚动到底部 - 在底部显示加载状态指示器
- 加载更多数据并追加到现有列表
六、动画与过渡效果
6.1 列表项动画
我们可以为列表项添加进入和退出动画,提升用户体验:
// 定义列表项动画
@State listItemAnimation: AnimateConfig = {
duration: 300,
curve: Curve.EaseOut,
delay: 0,
iterations: 1,
playMode: PlayMode.Normal
}
// 在GridItem中应用动画
GridItem() {
this.EnhancedProductCard(product)
}
.animation(this.listItemAnimation)
.transition({ type: TransitionType.Insert, opacity: 0, scale: { x: 0.8, y: 0.8 } })
.transition({ type: TransitionType.Delete, opacity: 0, scale: { x: 0.8, y: 0.8 } })
这段代码为列表项添加了动画效果:
- 新项目插入时有淡入和缩放效果
- 项目删除时有淡出和缩放效果
6.2 分类切换动画
我们可以为分类切换添加平滑的过渡动画:
@Builder
CategoryTabsWithAnimation() {
Scroll() {
Row() {
ForEach(this.categories, (category: CategoryType, index) => {
Column() {
Text(category.name)
.fontSize(14)
.fontColor(this.currentCategory === index ? '#FF5722' : '#333333')
.fontWeight(this.currentCategory === index ? FontWeight.Bold : FontWeight.Normal)
// 底部指示器
Row()
.width(24)
.height(3)
.borderRadius(1.5)
.backgroundColor('#FF5722')
.opacity(this.currentCategory === index ? 1 : 0)
.animation({
duration: 250,
curve: Curve.EaseInOut,
delay: 0,
iterations: 1,
playMode: PlayMode.Normal
})
}
.height(40)
.padding({ left: 16, right: 16 })
.margin({ right: 8 })
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.onClick(() => {
this.currentCategory = index;
this.filterProducts();
})
})
}
}
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.width('100%')
}
这段代码为分类选项卡添加了动画效果:
- 底部指示器有平滑的显示/隐藏动画
- 文字颜色和粗细有过渡效果
七、高级筛选功能
7.1 多维度筛选
我们可以实现多维度筛选功能,让用户可以根据多个条件筛选商品:
// 筛选条件
@State filterConditions: {
priceRange: [number, number],
categories: string[],
tags: string[],
ratings: number[]
} = {
priceRange: [0, 10000],
categories: [],
tags: [],
ratings: []
}
// 筛选面板UI
@Builder
AdvancedFilterPanel() {
Column() {
// 价格范围筛选
Column() {
Text('价格范围')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.width('100%')
Slider({
min: 0,
max: 10000,
step: 100,
value: this.filterConditions.priceRange[1],
style: SliderStyle.OutSet
})
.width('100%')
.margin({ top: 16, bottom: 16 })
.onChange((value: number) => {
this.filterConditions.priceRange[1] = value;
})
Row() {
Text(`¥${this.filterConditions.priceRange[0]}`)
.fontSize(14)
.fontColor('#666666')
Text(`¥${this.filterConditions.priceRange[1]}`)
.fontSize(14)
.fontColor('#666666')
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
}
.width('100%')
.padding(16)
Divider().color('#E5E5E5').width('100%')
// 分类筛选
Column() {
Text('分类')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.width('100%')
Flex({ wrap: FlexWrap.Wrap }) {
ForEach(this.categories.slice(1), (category: CategoryType) => {
Text(category.name)
.fontSize(14)
.fontColor(this.filterConditions.categories.includes(category.name) ? '#FFFFFF' : '#333333')
.backgroundColor(this.filterConditions.categories.includes(category.name) ? '#FF5722' : '#F5F5F5')
.padding({ left: 12, right: 12, top: 8, bottom: 8 })
.borderRadius(16)
.margin({ right: 8, bottom: 8 })
.onClick(() => {
// 切换分类选择状态
if (this.filterConditions.categories.includes(category.name)) {
this.filterConditions.categories = this.filterConditions.categories.filter(c => c !== category.name);
} else {
this.filterConditions.categories.push(category.name);
}
})
})
}
.width('100%')
.margin({ top: 16 })
}
.width('100%')
.padding(16)
Divider().color('#E5E5E5').width('100%')
// 标签筛选
Column() {
Text('标签')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.width('100%')
Flex({ wrap: FlexWrap.Wrap }) {
ForEach(['新品', '热卖', '促销', '包邮', '限时'], (tag: string) => {
Text(tag)
.fontSize(14)
.fontColor(this.filterConditions.tags.includes(tag) ? '#FFFFFF' : '#333333')
.backgroundColor(this.filterConditions.tags.includes(tag) ? '#FF5722' : '#F5F5F5')
.padding({ left: 12, right: 12, top: 8, bottom: 8 })
.borderRadius(16)
.margin({ right: 8, bottom: 8 })
.onClick(() => {
// 切换标签选择状态
if (this.filterConditions.tags.includes(tag)) {
this.filterConditions.tags = this.filterConditions.tags.filter(t => t !== tag);
} else {
this.filterConditions.tags.push(tag);
}
})
})
}
.width('100%')
.margin({ top: 16 })
}
.width('100%')
.padding(16)
// 确认和重置按钮
Row() {
Button('重置')
.fontSize(16)
.fontColor('#666666')
.backgroundColor('#F5F5F5')
.width('48%')
.height(44)
.onClick(() => {
// 重置筛选条件
this.resetFilterConditions();
})
Button('确认')
.fontSize(16)
.fontColor('#FFFFFF')
.backgroundColor('#FF5722')
.width('48%')
.height(44)
.onClick(() => {
// 应用筛选条件
this.applyFilterConditions();
this.isFilterPanelVisible = false;
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.padding(16)
}
.width('100%')
.backgroundColor('#FFFFFF')
.borderRadius({ topLeft: 16, topRight: 16 })
}
// 应用筛选条件
applyFilterConditions() {
this.filteredProductList = this.productList.filter(product => {
// 价格范围筛选
if (product.price < this.filterConditions.priceRange[0] ||
product.price > this.filterConditions.priceRange[1]) {
return false;
}
// 分类筛选
if (this.filterConditions.categories.length > 0 &&
!this.filterConditions.categories.includes(product.category)) {
return false;
}
// 标签筛选
if (this.filterConditions.tags.includes('新品') && !product.isNew) {
return false;
}
if (this.filterConditions.tags.includes('热卖') && !product.isHot) {
return false;
}
// 其他标签筛选逻辑...
return true;
});
// 应用当前的排序
this.sortProducts();
}
这段代码实现了多维度筛选功能:
- 价格范围筛选:使用Slider组件选择价格范围
- 分类筛选:可以选择多个分类
- 标签筛选:可以选择多个标签(新品、热卖等)
- 提供重置和确认按钮
7.2 搜索与推荐
我们可以实现搜索和推荐功能,帮助用户更快找到所需商品:
@State searchKeyword: string = ''
@State searchHistory: string[] = []
@State searchSuggestions: string[] = []
// 搜索框UI
@Builder
EnhancedSearchBar() {
Column() {
Row() {
Image($r('app.media.ic_search'))
.width(20)
.height(20)
.margin({ right: 8 })
TextInput({ placeholder: '搜索商品', text: this.searchKeyword })
.width('80%')
.height(36)
.backgroundColor('transparent')
.onChange((value: string) => {
this.searchKeyword = value;
this.updateSearchSuggestions();
})
if (this.searchKeyword.length > 0) {
Image($r('app.media.ic_clear'))
.width(20)
.height(20)
.margin({ left: 8 })
.onClick(() => {
this.searchKeyword = '';
this.searchSuggestions = [];
})
}
}
.width('100%')
.height(48)
.borderRadius(24)
.backgroundColor('#F5F5F5')
.padding({ left: 16, right: 16 })
// 搜索建议
if (this.searchKeyword.length > 0 && this.searchSuggestions.length > 0) {
Column() {
ForEach(this.searchSuggestions, (suggestion: string) => {
Row() {
Image($r('app.media.ic_search_history'))
.width(16)
.height(16)
.margin({ right: 8 })
Text(suggestion)
.fontSize(14)
.fontColor('#333333')
.layoutWeight(1)
Image($r('app.media.ic_arrow_right'))
.width(16)
.height(16)
}
.width('100%')
.height(44)
.padding({ left: 16, right: 16 })
.onClick(() => {
this.searchKeyword = suggestion;
this.search();
})
if (this.searchSuggestions.indexOf(suggestion) < this.searchSuggestions.length - 1) {
Divider().color('#E5E5E5').width('100%').margin({ left: 16, right: 16 })
}
})
}
.width('100%')
.backgroundColor('#FFFFFF')
.borderRadius(8)
.margin({ top: 8 })
.shadow({
radius: 8,
color: 'rgba(0, 0, 0, 0.1)',
offsetX: 0,
offsetY: 2
})
}
}
.width('100%')
}
// 更新搜索建议
updateSearchSuggestions() {
if (this.searchKeyword.length === 0) {
this.searchSuggestions = [];
return;
}
// 模拟搜索建议
this.searchSuggestions = this.productList
.filter(product => product.name.toLowerCase().includes(this.searchKeyword.toLowerCase()))
.map(product => product.name)
.slice(0, 5);
}
// 执行搜索
search() {
if (this.searchKeyword.trim().length === 0) return;
// 保存搜索历史
if (!this.searchHistory.includes(this.searchKeyword)) {
this.searchHistory.unshift(this.searchKeyword);
if (this.searchHistory.length > 10) {
this.searchHistory.pop();
}
}
// 根据关键词过滤商品
this.filteredProductList = this.productList.filter(product => {
return product.name.toLowerCase().includes(this.searchKeyword.toLowerCase()) ||
product.category.toLowerCase().includes(this.searchKeyword.toLowerCase());
});
// 清空搜索建议
this.searchSuggestions = [];
}
这段代码实现了搜索和推荐功能:
- 实时搜索建议:输入关键词时显示匹配的商品名称
- 搜索历史记录:保存用户的搜索历史
- 搜索结果过滤:根据关键词过滤商品列表
八、完整代码结构
下面是进阶版卡片样式列表应用的完整功能和技术点总结:
功能模块 | 技术点 | 实现方式 |
---|---|---|
卡片样式高级定制 | 复杂布局、状态样式 | 使用Stack、Column、Row组件 + stateStyles |
主题化 | 动态颜色、AppStorage | 定义主题颜色 + StorageLink |
瀑布流布局 | WaterFlow组件 | WaterFlow + FlowItem + 动态高度计算 |
滑动操作 | SwipeAction组件 | SwipeAction + SwipeActionButton |
拖拽排序 | 拖拽事件 | draggable属性 + onDragStart/onDrop事件 |
下拉刷新 | Refresh组件 | Refresh + onRefresh回调 |
无限滚动加载 | 滚动事件 | onReachEnd事件 + 加载状态指示器 |
列表项动画 | 过渡动画 | animation + transition属性 |
多维度筛选 | 复杂筛选面板 | Slider、多选UI + 筛选逻辑 |
搜索与推荐 | 搜索建议、历史记录 | TextInput + 实时建议 + 历史记录 |
九、总结
本教程详细讲解了如何在HarmonyOS NEXT中实现一个具有进阶特性的卡片样式列表应用,通过这些进阶特性的实现,我们的卡片样式列表应用不仅具备了基本的商品展示功能,还拥有了更加精美的UI设计、更丰富的交互方式和更强大的功能。这些技术和思路不仅适用于电商应用,也可以应用到其他需要卡片式内容展示的场景中,如社交媒体、新闻应用、视频应用等。
- 0回答
- 4粉丝
- 0关注
- 151.[HarmonyOS NEXT 实战案例十二:List系列] 卡片样式列表组件实战:打造精美电商应用 基础篇
- 138.[HarmonyOS NEXT 实战案例七:List系列] 多列列表组件实战:打造精美应用推荐页 进阶篇
- 156.[HarmonyOS NEXT 实战案例十二 :List系列] 聊天消息列表 - 进阶篇
- 136.[HarmonyOS NEXT 实战案例七:List系列] 水平列表组件实战:打造精美图片库 进阶篇
- 142.[HarmonyOS NEXT 实战案例九:List系列] 分组列表组件实战:打造分类设置菜单 进阶篇
- 134.[HarmonyOS NEXT 实战案例六:List系列] 垂直列表组件实战:打造高效联系人列表 进阶篇
- 144.[HarmonyOS NEXT 实战案例十:List系列] 字母索引列表组件实战:打造高效联系人应用 进阶篇
- 140.[HarmonyOS NEXT 实战案例八:List系列] 滑动操作列表组件实战:打造高效待办事项应用 进阶篇
- 137.[HarmonyOS NEXT 实战案例七:List系列] 多列列表组件实战:打造精美应用推荐页 基础篇
- [HarmonyOS NEXT 实战案例:电商应用] 进阶篇 - 交互功能与状态管理
- [HarmonyOS NEXT 实战案例:电商应用] 进阶篇 - 交互功能与状态管理
- 148.[HarmonyOS NEXT 实战案例八 :List系列] 粘性头部列表进阶篇
- 150.[HarmonyOS NEXT 实战案例十一:List系列] 下拉刷新和上拉加载更多列表组件实战:打造高效新闻应用 进阶篇
- 146.[HarmonyOS NEXT 实战案例七 :List系列] 可选择列表进阶篇
- 157.[HarmonyOS NEXT 实战案例一:Grid] 基础网格布局:打造精美电商商品列表