尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

乒乓球口袋教练 HarmonyOS 学习应用(05):搜索与分类组合过滤

乒乓球口袋教练 HarmonyOS 学习应用(05):搜索与分类组合过滤
📅 发布时间:2026/7/30 12:09:42

一、把关键词和专项筛选放进同一个查询入口

课程多起来以后,用户常常先输入“反手”,再把范围切到相持模块。若关键词和模块按钮分别在页面各自过滤,列表条数、课程标签和点击后的详情很容易不一致。本项目把两个条件交给 SearchService.search:keyword 先 trim 并转小写,moduleId 决定课程范围,再对标题、描述、关键词和子分类标签做同一轮匹配。

// 简单全字段匹配:标题 + 描述 + 关键词 + 子分类标签 export class SearchService { static search(keyword: string, moduleId?: string): SearchHit[] { const kw: string = keyword.trim().toLowerCase(); return COURSES .filter(c => moduleId === undefined || moduleId === 'all' || c.moduleId === moduleId) .filter(c => SearchService.matches(c, kw)) .map<SearchHit>((c: Course): SearchHit => { const m: LearnModule | undefined = findModule(c.moduleId); return { course: c, moduleTitle: m?.title ?? '' } as SearchHit; }); } private static matches(c: Course, kw: string): boolean { if (kw.length === 0) return true; if (c.title.toLowerCase().indexOf(kw) >= 0) return true; if (c.desc.toLowerCase().indexOf(kw) >= 0) return true; if (c.subCategoryLabel.indexOf(kw) >= 0) return true; for (const k of c.keywords) { if (k.toLowerCase().indexOf(kw) >= 0) return true; } return false; }

二、空关键词并不等于跳过模块边界

模块条件的 all 不是删除筛选逻辑,而是显式表示“允许所有 moduleId”。因此空关键词时仍会返回当前模块的完整课程集合;输入词后也不会意外跨到发球或战术模块。这个约束让顶部筛选按钮和搜索框是两个输入,却只有一个可解释的结果集合。

参与者输入输出或约束
模型或配置稳定标识、模式或模块字段给出可追溯的工程事实
服务或系统能力经过归一化的请求返回明确结果或失败原因
页面回读后的结果只渲染,不保存第二份事实
} private hits(): SearchHit[] { return SearchService.search(this.keyword, this.moduleFilter); } @Builder resultSection() { Column() { if (this.hits().length === 0) { EmptyState({ emoji: '🔍', title: '未找到相关内容', subtitle: '换个关键词试试,或在分类里浏览' }); } else { this.resultTitle(); Column({ space: AppSizes.s2 }) { ForEach(this.hits(), (h: SearchHit) => { this.hitRow(h); }, (h: SearchHit) => h.course.id); } .padding({ left: AppSizes.s4, right: AppSizes.s4 });

三、命中结果为何要带回匹配字段

SearchHit 不只保存课程对象,还保留 matchedFields。页面可以提示用户命中的是标题、描述还是关键词,而不是把所有结果都说成标题匹配。对于“旋转”这类可能出现在描述中的词,这比只调用 title.includes 更接近用户的真实预期,也让后续高亮有稳定来源。

Column({ space: AppSizes.s2 }) { ForEach(this.hits(), (h: SearchHit) => { this.hitRow(h); }, (h: SearchHit) => h.course.id); } .padding({ left: AppSizes.s4, right: AppSizes.s4 }); } } .width('100%'); } @Builder resultTitle() { Row() { Text('搜索结果(' + this.hits().length + ')') .fontSize(AppText.fsTitle) .fontWeight(AppText.fwSemi) .fontColor(this.palette.textPrimary) .layoutWeight(1); } .width('100%') .padding({ left: AppSizes.s4, right: AppSizes.s4, top: AppSizes.s2, bottom: AppSizes.s2 }); }

四、搜索页和课程详情怎样交接

点击命中项后,SearchPage 传递的是 course.id;课程详情再按 id 查回模型。这样搜索结果不会把一份旧课程对象塞进路由,也不会因为返回搜索页而保留已经失效的对象。找不到 id 时应留在可解释的结果或空态,不能拼一个默认课程继续播放。

情况容易出现的错误本文采用的处理
数据或配置缺项伪造默认成功状态停在可解释的失败或空态
页面重进使用上一页残留对象从模型、服务或系统重新回读
重复动作再写一遍相同业务事实由稳定入口或回调收敛
import { packagedVideoFileName } from './CourseVideoAssets'; export interface Course { id: string; moduleId: string; subCategory: string; subCategoryLabel: string; title: string; desc: string; thumbKey: string; videoSrc?: string; durationSec: number; order: number; intro: Block[]; keyPoints: Block[]; mistakes: Block[]; training: Block[]; keywords: string[]; externalVideoRefs?: ExternalVideoRef[]; } export interface SubCategory { id: string;

五、筛选回归要观察哪些具体结果

回归时先在全部范围搜索一个只出现在关键词中的动作术语,再切到不含该术语的专项确认结果归零;随后清空关键词,确认当前专项课程恢复;最后点击一条命中课程、返回并重进搜索页,检查标题、专项标签和命中字段仍来自同一条查询链路。

验收阶段实际动作回读重点
前置确认启动正确 bundle 或打开目标页标题、入口与模块身份
主题操作执行搜索、切换、完成或跳转服务/系统返回的结果
重进检查返回、重启或切换范围后再进入事实没有依赖旧页面残留

六、实现边界与维护顺序

搜索词、专项模块和课程字段在同一条查询链路中收敛,避免页面分别筛选后出现标题、分类与结果数量互相矛盾。 新增需求时应先补齐模型、配置或服务合同,再调整页面入口;把同一个判断复制到多个组件,短期看似方便,后续会使结果无法回读。ArkTS 状态管理的基础机制可参考 HarmonyOS 官方文档。

七、继续扩展时的约束

搜索条件的归一化必须早于排序。先把关键词转换为可比较的值,再确定模块范围,最后计算匹配字段,结果才能稳定复现。若把排序写在页面中,用户从课程详情返回后可能看到同一关键词却是另一种顺序,测试也无法知道变化来自课程数据还是渲染时机。

对于不存在的 moduleId,服务不应该宽容地退回全部课程;那会让路由或按钮传错参数时看起来仍有结果。明确返回空集合配合页面空态,更容易暴露调用链错误。真正需要全量搜索时,调用方显式传 all,使阅读代码的人一眼能看懂扩大范围是有意的。

后续若加入历史搜索或远程建议词,历史项只保存用户输入,不缓存旧 SearchHit。重新打开历史词时仍需经过当前 SearchService,这样课程下架、关键词修改和模块调整才能立刻反映到结果中。

结果数量为何必须从命中集合计算

搜索页标题中的数量直接来自 hits().length,而不是由输入框事件维护一个计数器。前者会随关键词、模块和课程模型重算,后者容易在清空输入、返回页面或课程数据变化后留下旧数字。对于用户而言,数量、每一行课程和命中说明应始终是同一集合的三个投影。

匹配规则改变时怎样验收

增加一个关键词字段后,要准备标题不含该词但 keywords 含该词的课程,确认它被召回;再准备同词但不同模块的课程,确认模块筛选排除它。两组数据分别覆盖匹配能力和范围能力,不能只用一条“搜索成功”的截图混在一起。

相关新闻

  • 成人纸尿裤生产线设备源头工厂
  • 智能体开发之MCP协议从理论到实践
  • 乒乓球口袋教练 HarmonyOS 学习应用(06):主题 Token 与球台视觉风格

最新新闻

  • STM32嵌入式开发:RT-Thread FINSH组件实战配置与优化指南
  • Apache服务器安全加固最佳实践与配置指南
  • 学校校门改造,悬浮门到底适不适合? - 星泽吖
  • 三方监理视角:解码家装质量监管新逻辑 - 城刊速递
  • 4399小游戏数据爬取实战:DrissionPage动态网页抓取与反爬策略
  • LangChain 1.3.11与LangGraph:从RAG系统搭建到多智能体工作流实战

日新闻

  • 终极TeamSpeak3音乐机器人搭建指南:5分钟实现语音聊天室音频播放
  • 广州海珠区内搬家攻略,平价靠谱搬家服务商推荐,专业打包搬运省心避坑全流程指南 - 厚道搬家
  • 大语言模型入门指南:从零到精通掌握AI核心技术的5大步骤

周新闻

  • 大连理工大学与东京大学联手打造的“主动型AI助手“
  • 170.2026年国家级科研瓶颈:超精密单点金刚石切削(SPDT)光学表面生成
  • SongBloom:革命性歌曲生成框架深度解析——如何通过交织自回归与扩散模型创作完整音乐

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号