HarmonyOS知识库——笔记列表的多源数据与实时搜索

发布时间:2026/9/29 4:03:52

HarmonyOS知识库——笔记列表的多源数据与实时搜索
知识库 App 的 NoteList 是一个万能列表页——从不同入口进来时显示不同数据从笔记本卡片进来显示该笔记本的笔记从搜索 tab 进来显示全部笔记从标签进来显示该标签的笔记。同一个页面承载三种数据源靠的是路由参数的灵活判断。完整效果一、三种数据来源的路由参数设计入口参数数据源标题首页笔记本卡片notebookId notebookNamegetNotesByNotebook(id)笔记本名称如工作底部导航搜索notebookId-1, notebookName‘全部笔记’getNotes()“全部笔记”标签页 TagFilterPage无直接调 searchNotessearchNotes(keyword)“搜索结果”三种来源走不同的查询函数aboutToAppear():void{constprouter.getParams()asRecordstring,Objectif(p){if(p[notebookId]){constid:numberp[notebookId]asnumberthis.notesid0?getNotes():getNotesByNotebook(id)this.titlep[notebookName]asstring}}}id 0 ? getNotes() : getNotesByNotebook(id)的特殊值判断。notebookId-1 是一个约定值——表示不按笔记本筛选显示全部笔记。NoteList 收到 -1 后走getNotes()收到其他值走getNotesByNotebook(id)。为什么不传 notebookId 来表示全部笔记因为 router.getParams() 返回的对象可能没有 notebookId 字段需要额外判断if (p[notebookId])。用 -1 这个约定值判断逻辑更简单——只需要比较数字。踩坑记录最初传了notebookId: 0但 NOTEBOOKS 里没有 id0 的笔记本getNotesByNotebook(0)返回空数组页面显示空白。改成 -1 后在 NoteList 里加了id 0判断解决。二、搜索功能的实时过滤StatesearchText:stringprivatedoSearch():void{this.notesthis.searchText.trim().length0?searchNotes(this.searchText):getNotes()}// 搜索框TextInput({placeholder:搜索笔记...,text:this.searchText}).layoutWeight(1).height(36).fontSize(14).backgroundColor(#F5F5FA).borderRadius(18).padding({left:14}).onChange((v:string){this.searchTextv;this.doSearch()})搜索框的 onChange 同时做两件事同步搜索词到 State然后调用 doSearch 重新过滤。用户每打一个字都会触发过滤——实时响应。doSearch 的二分支逻辑搜索词非空时调用searchNotes(keyword)为空时调用getNotes()恢复全部笔记。这个恢复逻辑很重要——用户清空搜索框后应该看到全部笔记而不是空列表。搜索词为空时为什么调 getNotes() 而不是 getNotesByNotebook()因为搜索是全局搜索——不限定笔记本。清空搜索词后恢复全部笔记更符合用户预期。踩坑记录最初搜索词为空时没有恢复逻辑用户搜完后清空搜索框列表还是空的。加了getNotes()恢复后解决。三、getNotesByNotebook 的双重遍历exportfunctiongetNotesByNotebook(nbId:number):Note[]{constr:Note[][]for(leti:number0;i_notes.length;i){if(_notes[i].notebookIdnbId)r.push(_notes[i])}returnr}单层遍历——比 getFavs 的双重遍历简单。因为 Notebook 的关联是单向的——笔记直接存了 notebookId不需要额外匹配。菜谱 App 的收藏需要遍历 RECIPES 和 _favs 两个数组做交叉匹配复杂度更高。返回新数组——r.push(_notes[i])创建了独立数组。调用方修改返回值不会影响 _notes。四、搜索结果的两种空状态NoteList 有两种空状态场景场景原因当前处理笔记本内没有笔记该笔记本是空的显示空白搜索无结果关键词没有匹配显示空白当前两种空状态都没有提示——页面只有导航栏和空白区域。优化方案if(this.notes.length0){Column(){Text(this.searchText.length0?:).fontSize(48).opacity(0.2).margin({bottom:12})Text(this.searchText.length0?没有找到相关笔记:还没有笔记).fontSize(14).fontColor(T2)Text(this.searchText.length0?试试其他关键词:点击 新建一篇).fontSize(12).fontColor(T3).margin({top:4})}.width(100%).layoutWeight(1).justifyContent(FlexAlign.Center)}根据搜索状态显示不同的空状态文案。有搜索词时提示没有找到相关笔记没有搜索词时提示还没有笔记。两种场景的解决方案不同——前者建议换关键词后者建议新建笔记。五、笔记卡片的信息精简Row(){Text(this.nbIcon(n.notebookId)).fontSize(20).width(44).height(44).borderRadius(12).backgroundColor(this.nbColor(n.notebookId)12).textAlign(TextAlign.Center)Column(){Row(){Text(n.title).fontSize(14).fontWeight(FontWeight.Bold).fontColor(T1).maxLines(1).layoutWeight(1)if(n.favorited)Text(❤️).fontSize(12)}Text(this.nbName(n.notebookId) · n.createdAt).fontSize(10).fontColor(T3).margin({top:2})}.alignItems(HorizontalAlign.Start).margin({left:10}).layoutWeight(1)SymbolGlyph($r(sys.symbol.chevron_right)).fontSize(14).fontColor([#DDD])}和首页笔记卡片的对比部分首页卡片NoteList 卡片第一行标题 收藏图标标题 收藏图标第二行内容预览前 50 字笔记本名称 日期第三行笔记本标签 日期 标签无右侧箭头无有NoteList 卡片比首页卡片更精简——去掉了内容预览和标签。原因是NoteList 可能显示很多笔记全部 12 篇或搜索结果精简的卡片让用户一屏能看到更多条目。首页是仪表盘需要展示更多信息密度所以加了内容预览和标签。信息密度的选择取决于使用场景仪表盘首页高密度一屏展示尽量多信息列表页NoteList中密度平衡信息量和浏览效率空状态零密度留白引导用户操作六、nbName/nbIcon/nbColor 的重复出现NoteList、FavoritesPage、TagFilterPage 三个页面都有这三个辅助函数privatenbName(id:number):string{...}privatenbIcon(id:number):string{...}privatenbColor(id:number):string{...}三个函数结构完全一样——只是返回的字段不同。这是抽取公共函数的典型场景。两种抽取方案方案一抽取到 NoteService 数据层// NoteService.ets 新增exportfunctiongetNotebookName(id:number):string{...}exportfunctiongetNotebookIcon(id:number):string{...}exportfunctiongetNotebookColor(id:number):string{...}三个页面直接导入调用不需要各自定义。优点是代码零重复缺点是数据层承担了 UI 相关的职责图标和颜色是展示逻辑。方案二保持各自定义三个页面各自写一份。代码有重复但每个页面自包含——不依赖其他页面或额外的函数。在 6 个页面的规模下重复代码的维护成本可以接受。当前选了方案二。原因是知识库 App 只有 3 个页面用到这三个函数重复量不大。如果以后增加到 10 页面都用到再抽取也不迟。七、整体嵌套结构Column 页面容器 ├→ Row (导航栏) 返回 标题 数量 ├→ Row (搜索框) 搜索图标 TextInput └→ Scroll 可滚动内容 └→ Column({ space: 8 }) 垂直排列笔记卡片 ├→ ForEach(this.notes, ...) 笔记卡片列表 └→ Blank(20) 底部留白嵌套深度只有 3 层——比首页少一层。因为没有底部导航栏不需要 Stack 层叠。这是列表页的标准结构导航栏 搜索框 列表三层嵌套足够。搜索框在导航栏和列表之间。这是移动端搜索列表的标准位置——用户先看到标题再看到搜索框最后看到列表。搜索框靠近列表让视觉焦点集中在搜索 → 结果的流程上。八、数据流的完整链路入口一首页笔记本卡片 → router.pushUrl({ notebookId: 1, notebookName: 工作 }) → NoteList.aboutToAppear → getNotesByNotebook(1) → this.notes 3 篇工作笔记 → ForEach 渲染列表 入口二底部导航搜索 → router.pushUrl({ notebookId: -1, notebookName: 全部笔记 }) → NoteList.aboutToAppear → getNotes() (id 0) → this.notes 12 篇全部笔记 → ForEach 渲染列表 用户在搜索框输入HarmonyOS → onChange → doSearch → searchNotes(HarmonyOS) → this.notes 1 篇匹配笔记 → ForEach 重新渲染三种入口最终都走到同一个 ForEach 渲染逻辑。数据来源不同但 UI 结构完全一样。这就是一个页面多种数据源的架构优势——只需要一套卡片组件不同数据源只需切换查询函数。九、和其他列表页的对比维度NoteListFavoritesPageTagFilterPage数据来源三种全部/按笔记本/搜索一种收藏两种标签列表/按标签筛选搜索功能有实时过滤无无空状态无有无标签展示无无有标签网格代码量最多最少中等NoteList 是三个列表页里功能最全的——有搜索、有多种数据源。FavoritesPage 最简单——只显示收藏笔记。TagFilterPage 介于两者之间——有两种状态标签列表/筛选结果。

相关新闻

Uncle小说阅读器:一站式PC端数字阅读解决方案终极指南

Uncle小说阅读器:一站式PC端数字阅读解决方案终极指南

2026/9/26 3:31:39

Uncle小说阅读器:一站式PC端数字阅读解决方案终极指南 【免费下载链接】uncle-novel 📖 Uncle小说,PC版,一个全网小说下载器及阅读器,目录解析与书源结合,支持有声小说与文本小说,可下载mobi、e…

TDA3x处理器接口信号深度解析:从引脚定义到硬件设计实战

TDA3x处理器接口信号深度解析:从引脚定义到硬件设计实战

2026/9/5 16:29:21

1. 项目概述:为什么接口信号是嵌入式设计的“交通规则”在嵌入式硬件设计的江湖里,处理器就像一座繁忙的城市核心,而接口信号就是连接这座核心与外部世界(传感器、存储器、通信模块)的条条道路和交通规则。你可能会觉得…

如何高效解决Windows上HEIF图片兼容性问题:免费开源工具完整指南

如何高效解决Windows上HEIF图片兼容性问题:免费开源工具完整指南

2026/8/23 0:16:17

如何高效解决Windows上HEIF图片兼容性问题:免费开源工具完整指南 【免费下载链接】HEIF-Utility HEIF Utility - View/Convert Apple HEIF images on Windows. 项目地址: https://gitcode.com/gh_mirrors/he/HEIF-Utility 还在为iPhone拍摄的照片在Windows电…

CANN/GE ACL数据集缓冲区添加函数

CANN/GE ACL数据集缓冲区添加函数

2026/9/28 4:08:17

aclmdlAddDatasetBuffer 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、Te…

用ffmpeg高效批量调整图片尺寸的实战指南

用ffmpeg高效批量调整图片尺寸的实战指南

2026/9/28 16:01:49

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

2026/9/28 2:15:29

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱 【免费下载链接】transformers 🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and mu…

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

2026/9/28 3:14:54

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system sup…

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

2026/9/28 3:58:00

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

2026/9/28 3:47:14

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system supporting mi…

远程协作的工作台整理

远程协作的工作台整理

2026/9/28 16:01:48

远程协作的工作台整理远程协作的核心不是再加一个工具,而是让交接信息足够完整。异步任务要写明目标、输入位置、完成标准和需要决策的人。 工作台的最小配置 将日程、待办、代码和沟通入口收拢到少数固定位置;通知按紧急程度分层。工作台不需要模仿办公…

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

2026/9/28 5:05:21

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

2026/9/28 16:01:48

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…