效果图展示:

代码截图注释


详情实现笔记
总体目标(按需求点对照代码)
- 数据模块化、整体渲染框架、筛选/排序的高亮与行为,全部已在
Index.ets
+ CarData.ets
落地。下面按图片需求 2~4 点逐条总结,并给出关键代码定位与“为什么”。
1. 数据模块化(数据模型/源)
CarData.ets
定义强类型模型 Car
与静态数据源 carList
,页面只依赖这一个入口。
export interface Car {count: number // 销量image: ResourceStr // 图片series_name: string // 名字rank: number // reduce(热度)id: number // idmin_price: number // 最低价max_price: number // 最高价type: number // 类型 1紧凑汽车 2微型车 3小型车 4中型车
}
- 页面引入并作为状态初始化,后续所有筛选/排序都基于它更新渲染列表。
import { Car, carList } from '../models/CarData'
@State carList: Car[] = carList//汽车的列表
@State scaleX: number = 1
@State scaleY: number = 1
- 为什么:强类型防止字段误用;把“原始数据池”与“渲染状态”分离,筛选始终从全量数据重新计算,结果可预期。
2. 渲染汽车列表
- 2.1 基于提供的数据渲染
List
列表(图片、名称、价格、销量)。
List({ space: 10 }) {ForEach(this.carList, (item: Car, index: number) => {ListItem() {Row({ space: 8 }) {// 名次图标/数字见下节Image(item.image).width(100).syncLoad(true)Column({ space: 10 }) {Text(item.series_name)Text(item.min_price.toFixed(2) + '-' + item.max_price.toFixed(2) + '万').fontColor(Color.Orange).fontSize(15)}
- 2.2 前三名用奖牌图,之后用序号
index+1
。
if (index === 0) {Image($r('app.media.ic_homework_first')).width(40)
} else if (index == 1) {Image($r('app.media.ic_homework_second')).width(40)
} else if (index === 2) {Image($r('app.media.ic_homework_third')).width(40)
} else {Text((index + 1).toString()).fontSize(25)
}
3. 渲染“筛选区/排序区”高亮切换
filterList = ['全部', '紧凑型车', '微型车', '小型车', '中型车',]
@State filterListActiveIndex: number = 0
ForEach(this.filterList, (item: string, index: number) => {Text(item).fontColor(this.filterListActiveIndex === index ? Color.Red : '#595B5D')
sortList = ['热度', '价格', '销量']
@State sortListActiveIndex: number = 0
ForEach(this.sortList, (item: string, index: number) => {Text(item).fontColor(this.sortListActiveIndex === index ? Color.Red : Color.Black)
- 为什么:用
@State
保存当前索引,通过条件 fontColor
切换高亮,点击只需改索引即可即时反馈。
4. 实现筛选与排序效果
- 4.1 筛选:点击车型标签 → 过滤对应列表并渲染。
.onClick(() => {this.filterListActiveIndex = index
this.carList = carList.filter((ele: Car, index) => {return item === '全部' ? true : ele.type === this.filterListActiveIndex
})
})
- 为什么:每次都基于“原始 carList”过滤,避免在上一次结果上叠加筛选造成数据越来越少;利用“索引=type 值”的约定实现最短判断。
- 4.2 排序:点击排序项 → 对当前数组排序
this.sortListActiveIndex = index
this.carList = this.carList.sort((a: Car, b: Car) => {if (this.sortListActiveIndex === 0) { // 4.2.1 热度return a.rank - b.rank // rank 升序} else if (this.sortListActiveIndex === 1) {// 4.2.2 价格return (a.max_price - a.min_price) - (b.max_price - b.min_price)} else { // 4.2.3 销量return b.count - a.count // 降序}
})
- 为什么:先筛后排符合用户习惯;对“当前结果集”排序即可;
sort
原地排序效率高并配合赋值触发 UI 更新。 - 注意与需求对齐:
- 需求 4.2.2 写的是“max_price 降序”。当前实现是“价格区间宽度升序”。若要与需求一致,应改为:
- 价格(最高价降序)比较器:
(a, b) => b.max_price - a.max_price
额外:按钮动画
Text('询底价').backgroundColor('#027DFF').padding(5).borderRadius(3).fontColor('#fff').scale({ x: this.scaleX, y: this.scaleY }).onAppear(() => { this.scaleX = 1.1; this.scaleY = 1.1 }).animation({ iterations: -1, playMode: PlayMode.AlternateReverse })
- 为什么:出现即启动无限往返缩放,形成“呼吸”吸引点击。
小结与对齐校验
- 整体渲染:顶部标题/图标 + 筛选条 + 时间/排序 + 列表,结构完整;前三名奖牌与序号展示符合 2.2。
- 高亮:筛选与排序均用
@State
索引控制,点击即时变色。 - 筛选:点击车型后基于全量数据按
type
过滤,符合 4.1。 - 排序:热度升序、销量降序已符合 4.2.1/4.2.3;价格需将比较器改为“max_price 降序”以完全符合 4.2.2。
全部代码:
CarData_接口和数据
export interface Car {count: number // 销量image: ResourceStr // 图片series_name: string // 名字rank: number // reduce(热度)id: number // idmin_price: number // 最低价max_price: number // 最高价type: number // 类型 1紧凑汽车 2微型车 3小型车 4中型车
}
export const carList: Car[] = [{count: 30001,image: 'http://p6-dcd.byteimg.com/img/tos-cn-i-dcdx/2b0405ab3ec543bf9bef91533b82899f~tplv-resize:480:0.png',series_name: '凯美瑞',rank: 1,id: 535,min_price: 17.18,max_price: 20.68,type: 4,},{count: 30456,image: 'http://p6-dcd.byteimg.com/img/motor-mis-img/af835d978de92b8342d900c8473c8d88~tplv-resize:480:0.png',series_name: '思域',rank: 2,id: 276,min_price: 9.69,max_price: 15.49,type: 1,},{count: 32178,image: 'http://p9-dcd.byteimg.com/img/tos-cn-i-dcdx/76d8b7dd596a42668c660711eb63ba36~tplv-resize:480:0.png',series_name: '欧拉黑猫',rank: 3,id: 2911,min_price: 5.98,max_price: 10.28,type: 2,},{count: 35690,image: 'http://p3-dcd.byteimg.com/img/tos-cn-i-dcdx/b16feb96960c4b178686faea93e71f3c~tplv-resize:480:0.png',series_name: '秦PLUS DM-i',rank: 4,id: 4802,min_price: 7.98,max_price: 12.58,type: 1,},{count: 37045,image: 'http://p9-dcd.byteimg.com/img/tos-cn-i-dcdx/c582d200e0fe44c7b1b5f3b6134c8849~tplv-resize:480:0.png',series_name: '小蚂蚁',rank: 5,id: 1101,min_price: 5.69,max_price: 8.9,type: 2,},{count: 38967,image: 'http://p1-dcd.byteimg.com/img/tos-cn-i-dcdx/db765ed4695e4d1e808f3344a2637ff8~tplv-resize:480:0.png',series_name: '奥迪A4L',rank: 6,id: 96,min_price: 23.17,max_price: 29.26,type: 4,},{count: 40321,image: 'http://p1-dcd.byteimg.com/img/tos-cn-i-dcdx/a6ee19f8cb8b4ad8bab7f2b3cb0e4fa1~tplv-resize:480:0.png',series_name: 'Polo',rank: 7,id: 391,min_price: 6.39,max_price: 9.79,type: 3,},{count: 42768,image: 'http://p1-dcd.byteimg.com/img/motor-mis-img/5a66c6bc0c1d71c7e6f68f53b902d1b9~tplv-resize:480:0.png',series_name: '奔奔E-Star',rank: 8,id: 4416,min_price: 6.69,max_price: 6.69,type: 2,},{count: 45603,image: 'http://p3-dcd.byteimg.com/img/tos-cn-i-dcdx/b904c6bfc5094657bbcad15af499fd16~tplv-resize:480:0.png',series_name: '飞度',rank: 9,id: 283,min_price: 6.98,max_price: 9.18,type: 3,},{count: 47892,image: 'http://p6-dcd.byteimg.com/img/motor-mis-img/b4f69ed40e9e2f4f40a8874ce323e181~tplv-resize:480:0.png',series_name: '宝马 3 系',rank: 10,id: 145,min_price: 24,max_price: 32.8,type: 4,},{count: 49103,image: 'http://p1-dcd.byteimg.com/img/motor-mis-img/5a47279a2f425d7c1505b60d0478d9a8~tplv-resize:480:0.png',series_name: '威驰',rank: 11,id: 538,min_price: 7.38,max_price: 9.48,type: 3,},{count: 50048,image: 'http://p6-dcd.byteimg.com/img/motor-mis-img/28d677a5f94a5a24103f088dd94c8515~tplv-resize:480:0.png',series_name: '朗逸',rank: 12,id: 393,min_price: 7.2,max_price: 11.39,type: 1,},{count: 50569,image: 'http://p3-dcd.byteimg.com/img/motor-mis-img/44c013067df2032cc03b6031eb68bf05~tplv-resize:480:0.png',series_name: '速腾',rank: 13,id: 414,min_price: 9.19,max_price: 13.69,type: 1,},{count: 51377,image: 'http://p9-dcd.byteimg.com/img/motor-mis-img/89991e9322440768e5f67b551d6e7ee5~tplv-resize:480:0.png',series_name: '迈腾',rank: 14,id: 415,min_price: 14.79,max_price: 21.49,type: 4,},{count: 52486,image: 'http://p1-dcd.byteimg.com/img/motor-mis-img/71bb241f24d3e20b2ee3adca8b6559fe~tplv-resize:480:0.png',series_name: '比亚迪e1',rank: 15,id: 3174,min_price: 5.99,max_price: 7.99,type: 2,},{count: 53098,image: 'http://p9-dcd.byteimg.com/img/tos-cn-i-dcdx/f5483079e6094fb898c14f3b3d6c1493~tplv-resize:480:0.png',series_name: '轩逸',rank: 16,id: 1145,min_price: 6.98,max_price: 14.19,type: 1,},{count: 54326,image: 'http://p6-dcd.byteimg.com/img/motor-mis-img/0d4b71e7270960f73f1e9370febad7cc~tplv-resize:480:0.png',series_name: 'YARiS L 致炫',rank: 17,id: 533,min_price: 6.88,max_price: 10.88,type: 3,},{count: 55067,image: 'http://p3-dcd.byteimg.com/img/tos-cn-i-dcdx/287e133f10e1402386d901c399885fbf~tplv-resize:480:0.png',series_name: '五菱宏光MINIEV',rank: 18,id: 4499,min_price: 2.98,max_price: 9.99,type: 2,},{count: 56234,image: 'http://p1-dcd.byteimg.com/img/motor-mis-img/69904c721ef8a45afecf7d777a1806ef~tplv-resize:480:0.png',series_name: 'MINI',rank: 19,id: 38,min_price: 18.98,max_price: 34.33,type: 3,},{count: 58973,image: 'http://p9-dcd.byteimg.com/img/tos-cn-i-dcdx/01ea2955a1cb44ff8f048e3deabf2c17~tplv-resize:480:0.png',series_name: '雅阁',rank: 20,id: 289,min_price: 12.58,max_price: 17.48,type: 4,},
]
界面结构和逻辑代码
import { Car, carList } from '../models/CarData'
@Entry
@Component
struct Page11_carHome {// 筛选条件filterList = ['全部', '紧凑型车', '微型车', '小型车', '中型车',]//筛选车型的默认高亮下标@State filterListActiveIndex: number = 0// 排序条件sortList = ['热度', '价格', '销量']//每种车型的(热度, 价格, 销量)筛选默认的高亮@State sortListActiveIndex: number = 0//汽车列表筛@State carList: Car[] = carList//汽车的列表@State scaleX: number = 1@State scaleY: number = 1// 获取当前时间(年月日)getTime() {const date: Date = new Date()const year = date.getFullYear()const month = date.getMonth() + 1const day = date.getDate()return `${year}年${month}月${day}日`}build() {Column() {// 顶部区域Stack() {Text('汽车之家排行榜').fontSize(18)Row({ space: 5 }) {Image($r('app.media.ic_public_arrow_left')).width(25)Blank()Image($r('app.media.ic_public_share')).width(25)Image($r('app.media.ic_public_question')).width(25)}.width('100%').padding(10)}Scroll() {Row({ space: 10 }) {// 筛选条件['全部', '紧凑型车', '微型车', '小型车', '中型车',]ForEach(this.filterList, (item: string, index: number) => {Text(item).fontColor(this.filterListActiveIndex === index ? Color.Red : '#595B5D').backgroundColor('#ccc').borderRadius(5).padding({top: 5,bottom: 5,left: 8,right: 8}).fontSize(14).onClick(() => {this.filterListActiveIndex = index// 注释的有误// // 车的类型// if (item === '全部') {// this.carList = carList.filter((ele: Car, index: number) => {// return true// })// }// else {// this.carList = carList.filter((ele: Car, index: number) => {// if (item === '紧凑车型') {// return ele.type===1// } else if (item === '微型车') {// return ele.type===2// } else if (item === '小型车') {// return ele.type===3// } else {// return ele.type===4// }// })// }// // 筛选// this.carListthis.carList = carList.filter((ele: Car, index) => {return item === '全部' ? true : ele.type === this.filterListActiveIndex})})})}.height(50).margin({left: 5,right: 5,bottom: 8}).border({ width: { bottom: 1 }, color: '#ccc' })}.height(50).scrollable(ScrollDirection.Horizontal).scrollBar(BarState.Off)// 排序条件(自己实现)Row() {Text(this.getTime())//时间(年月日显示).fontColor('#6D7177')Row({ space: 8 }) {// ['热度', '价格', '销量']ForEach(this.sortList, (item: string, index: number) => {Text(item).fontColor(this.sortListActiveIndex === index ? Color.Red : Color.Black).onClick(() => {this.sortListActiveIndex = index//列表的筛选this.carList =this.carList.sort((a: Car, b: Car) => {if (this.sortListActiveIndex === 0) {// 热度升序return a.rank - b.rank} else if (this.sortListActiveIndex === 1) {// 价格降序return (a.max_price - a.min_price) - (b.max_price - b.min_price)} else {// 销量降序return b.count - a.count}})})})}}.width('100%').justifyContent(FlexAlign.SpaceBetween).padding({top: 15,left: 10,right: 10,bottom: 15})// 列表区域(自己实现)List({ space: 10 }) {ForEach(this.carList, (item: Car, index: number) => {ListItem() {Row({ space: 8 }) {if (index === 0) {Image($r('app.media.ic_homework_first')).width(40)} else if (index == 1) {Image($r('app.media.ic_homework_second')).width(40)} else if (index === 2) {Image($r('app.media.ic_homework_third')).width(40)} else {Text((index + 1).toString()).fontSize(25)}Image(item.image).width(100).syncLoad(true)Column({ space: 10 }) {Text(item.series_name)Text(item.min_price.toFixed(2) + '-' + item.max_price.toFixed(2) + '万').fontColor(Color.Orange).fontSize(15)}.height('100%').layoutWeight(1).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Start)Column({ space: 6 }) {Text(item.count.toString()).fontWeight(700)Text('全国销量').fontColor('#67696C').fontSize(13)Text('询底价').backgroundColor('#027DFF').padding(5).borderRadius(3).fontColor('#fff').scale({ x: this.scaleX, y: this.scaleY }).onAppear(() => {this.scaleX = 1.1this.scaleY = 1.1}).animation({iterations: -1,playMode: PlayMode.AlternateReverse})}}}.width('100%').height(110)})}.width('100%').padding({ left: 10, right: 10 }).divider({strokeWidth: 1,color: '#ccc'}).scrollBar(BarState.Off)}.width('100%').height('100%')}
}