【OpenHarmony/HarmonyOs 】实验室首页细节拆解:分类侧栏、搜索筛选与推荐探索交互
【OpenHarmony/HarmonyOs 】实验室首页细节拆解:分类侧栏、搜索筛选与推荐探索交互
本文基于我的 OpenHarmony/HarmonyOS 项目「物理视界 PhysicsVision」整理。实验室首页是整个应用的核心入口,它承载了 28 个物理模型的分类展示、年级筛选、关键词搜索、最近浏览、推荐探索和随机探索。
这一篇单独拆实验室首页的交互细节,重点对应“全新视觉与交互体验”和“端侧智能推荐”的主题。🔬
一、实验室首页承担什么角色?
一个物理学习 App 不能只是把所有模型堆成一个列表。
如果模型数量多,用户很快会遇到几个问题:
- 不知道从哪里开始学;
- 找不到某个具体模型;
- 不清楚哪些模型适合自己年级;
- 学过的内容和没学过的内容混在一起;
- 每次打开都要重新寻找上次内容。
「物理视界」的实验室首页就是为了解决这些问题。它不是简单列表,而是一个学习入口:
- 左侧分类侧栏:按学科方向筛选;
- 年级筛选:按初中、高一、高二、高三定位;
- 搜索栏:按模型名、描述、分类、难度搜索;
- 推荐探索:优先推荐未学习的基础模型;
- 最近浏览:帮助用户回到上次学习;
- 随机探索:降低选择成本。
这些细节组合起来,就形成了一个很完整的学习流。
二、模型数据的结构化组织
实验室页中,模型不是孤立存在的,而是用多个数组维护元数据:
private names: string[] = [
'声音的传播', '光的反射', '串并联电路',
'匀变速直线运动', '自由落体', '力的合成与分解'
]
private descs: string[] = [
'探索声波在不同介质中的传播', '观察光线的反射规律',
'理解串联与并联电路特性', '研究匀变速运动的规律'
]
private gradeTags: string[] = [
'初中', '初中', '初中', '高一', '高一'
]
private categoryTags: string[] = [
'波动', '光学', '电磁学', '力学', '力学'
]
每个模型都有名称、描述、年级、分类、难度和路由。
这让首页可以做筛选、搜索、推荐、统计和跳转。
如果后续接入元服务或近场快传,这些结构化数据也能直接复用。
三、左侧分类侧栏:让知识结构更清楚
项目中分类包括:
private categories: string[] = ['全部', '力学', '电磁学', '光学', '热学', '波动']
侧栏每个分类都有图标和选中态:
ForEach(this.categories, (c: string, index: number) => {
Column({ space: 4 }) {
Image(this.catIconRes[index])
.width(20)
.height(20)
.fillColor(this.selectedCategory === index ? this.getCatAccent(index) : $r('app.color.icon_gray'))
Text(c)
.fontSize(10)
.fontWeight(this.selectedCategory === index ? FontWeight.Bold : FontWeight.Normal)
.fontColor(this.selectedCategory === index ? this.getCatAccent(index) : $r('app.color.text_sub'))
}
.backgroundColor(this.selectedCategory === index ? $r('app.color.bg_card') : Color.Transparent)
.borderRadius(12)
.onClick(() => {
animateTo({ duration: 200, curve: Curve.EaseOut }, () => {
this.selectedCategory = index
})
this.updateDisplayList()
})
})
这段代码体现了三个细节:
- 图标和文字都跟随选中态变化;
- 点击分类后有轻动画;
- 状态变化后立即刷新模型列表。
这种侧栏很适合知识型应用,因为它能把内容结构放在用户眼前。
四、年级筛选:贴合学习阶段
物理内容和年级强相关,所以项目提供了年级筛选:
private grades: string[] = ['全部', '初中', '高一', '高二', '高三']
筛选按钮使用轻量文本块:
ForEach(this.grades, (g: string, index: number) => {
Text(g)
.fontSize(11)
.fontWeight(this.selectedGrade === index ? FontWeight.Bold : FontWeight.Normal)
.fontColor(this.selectedGrade === index ? '#1A73E8' : $r('app.color.text_weak'))
.backgroundColor(this.selectedGrade === index ? $r('app.color.result_bg') : Color.Transparent)
.borderRadius(10)
.onClick(() => {
animateTo({ duration: 200, curve: Curve.EaseOut }, () => {
this.selectedGrade = index
})
this.updateDisplayList()
})
})
年级筛选可以避免学生一上来就看到太难的内容。
这也符合教育应用的基本原则:先让用户找到适合自己的学习层级。
五、搜索栏:多字段匹配
搜索不是只匹配名称,而是匹配多个字段:
let searchMatch: boolean = keyword.length === 0 ||
this.names[i].includes(keyword) ||
this.descs[i].includes(keyword) ||
this.categoryTags[i].includes(keyword) ||
this.gradeTags[i].includes(keyword) ||
this.difficulties[i].includes(keyword)
这意味着用户输入:
- “光学”可以找到光学模型;
- “高三”可以找到高三模型;
- “挑战”可以找到高难度内容;
- “电场”可以找到电场线、电场偏转。
对学习应用来说,搜索应该理解用户的意图,而不是只做标题匹配。
六、筛选主逻辑:分类、年级、搜索同时生效
完整筛选逻辑如下:
updateDisplayList(): void {
this.listAnim = false
let result: number[] = []
let keyword: string = this.searchText.trim()
for (let i = 0; i < this.names.length; i++) {
let categoryMatch: boolean = this.selectedCategory === 0 ||
this.categoryTags[i] === this.categories[this.selectedCategory]
let gradeMatch: boolean = this.selectedGrade === 0 ||
this.gradeTags[i] === this.grades[this.selectedGrade]
let searchMatch: boolean = keyword.length === 0 ||
this.names[i].includes(keyword) ||
this.descs[i].includes(keyword)
if (categoryMatch && gradeMatch && searchMatch) {
result.push(i)
}
}
this.displayList = result
}
这里使用的是“且”关系:
- 分类要匹配;
- 年级要匹配;
- 搜索要匹配。
这样筛选结果更精准。
七、推荐探索:项目里的端侧智能雏形
推荐逻辑优先找未探索的基础模型:
getRecommended(): number[] {
let result: number[] = []
for (let i = 0; i < this.names.length; i++) {
if (!this.isVisited(i) && this.difficulties[i] === '基础') {
result.push(i)
if (result.length >= 4) break
}
}
if (result.length < 4) {
for (let i = 0; i < this.names.length; i++) {
if (!this.isVisited(i) && this.difficulties[i] === '进阶') {
result.push(i)
if (result.length >= 4) break
}
}
}
return result
}
虽然这不是大模型 AI,但它是很实用的端侧智能:
- 不联网;
- 不上传用户数据;
- 根据本地学习状态推荐;
- 规则可解释。
对于教育应用来说,这种“本地可解释推荐”比黑盒推荐更可靠。
八、最近浏览:学习不断线
最近浏览列表取最近 6 个模型:
updateRecentList(): void {
if (this.visitedModels.length === 0) {
this.recentList = []
return
}
let parts: string[] = this.visitedModels.split(',')
let result: number[] = []
let start: number = parts.length > 6 ? parts.length - 6 : 0
for (let i = parts.length - 1; i >= start; i--) {
let val: number = parseInt(parts[i])
if (val >= 0 && val < this.names.length) {
result.push(val)
}
}
this.recentList = result
}
这个功能非常适合全场景智慧学习。
用户在手机上学过一个模型,后续如果做跨设备同步或备份恢复,就能在平板继续学习。
九、随机探索:降低选择压力
项目还提供随机探索:
navigateToRandom(): void {
let unvisited: number[] = []
for (let i = 0; i < this.names.length; i++) {
if (!this.isVisited(i)) unvisited.push(i)
}
let target: number = 0
if (unvisited.length > 0) {
target = unvisited[Math.floor(Math.random() * unvisited.length)]
} else {
target = Math.floor(Math.random() * this.names.length)
}
this.recordVisit(target)
router.pushUrl({ url: this.routes[target] }).catch(() => {})
}
它优先随机未探索模型,而不是完全随机。
这也是一个小小的学习引导:用户想不出学什么时,系统帮他迈出下一步。
十、总结
实验室首页的价值不只是展示模型,而是组织学习路径。
分类侧栏、年级筛选、关键词搜索、推荐探索、最近浏览、随机探索,这些功能共同构成了一个轻量但完整的学习入口。
这篇文章对应的主题是:全新视觉与交互体验 + 端侧智能推荐 + 全场景学习续接。
它没有脱离项目,因为所有细节都来自当前代码;它也没有空谈 AI,而是从本地学习状态出发,说明如何把一个模型列表做成真正可用的学习首页。🚀

更多推荐



所有评论(0)