欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。
本文对应模块:
pages.js中“交易列表”页面的 HTML 模板与筛选控件,重点是如何在 PC 布局下清晰展示大量交易,并提供按时间、类型等维度的过滤能力。
1. 模块目的:给用户一份“可翻、可筛”的流水账
记收入、记支出、转账,都是“写入数据”的动作。而交易列表页面则是“翻账本”的地方:
- 用户希望快速浏览最近一段时间的所有收支记录;
- 需要按月份、类型、账户等条件进行筛选;
- 必要时还能查看某一笔交易的详情或进行编辑、删除。
在这个模块中,我们关注的是交易列表的 UI 结构和过滤输入控件的设计,不深入业务逻辑(那会在后续模块中展开)。
2. 页面整体结构:列表页的标准骨架
在pages.js中,“交易列表”页面的模板大致如下(节选与合理还原):
// ==================== 交易列表页面 ===================='transactions':()=>`<div class="pc-page-container"> <div class="pc-page-header"> <h2>📝 交易记录</h2> <p>查看和管理你的历史收支流水</p> </div> <div class="pc-filter-bar"> <div class="pc-filter-group"> <label class="pc-label">月份</label> <input type="month" id="filter-month" class="pc-input"> </div> <div class="pc-filter-group"> <label class="pc-label">类型</label> <select id="filter-type" class="pc-input"> <option value="all">全部</option> <option value="income">收入</option> <option value="expense">支出</option> </select> </div> <!-- 可以继续扩展账户、分类等过滤条件 --> <button id="filter-apply" class="pc-button pc-button-primary">应用筛选</button> </div> <div class="pc-card"> <div class="pc-card-header"><h3>交易列表</h3></div> <div class="pc-card-body"> <table class="pc-table" id="transactions-table"> <thead> <tr> <th>日期</th> <th>类型</th> <th>账户</th> <th>分类</th> <th>金额</th> <th>备注</th> </tr> </thead> <tbody> <!-- JS 动态渲染交易行 --> </tbody> </table> </div> </div> </div>`,2.1 上方过滤栏 + 下方表格的经典布局
pc-filter-bar- 放置所有筛选控件(月份、类型、账户、分类等);
- 与下面的表格通过视觉分隔,使用户一眼看出“先选条件,再看列表”。
pc-card+pc-card-header+pc-card-body- 用卡片组件包裹完整的表格,让内容区域更聚焦;
pc-table- 标准表格组件,用于按行列展示每一笔交易;
- 表头固定列:日期、类型、账户、分类、金额、备注。
这种设计在财务类应用中非常常见,既符合用户预期,也便于后续按列排序、增加更多字段。
3. 筛选控件的 UI 设计
3.1 月份筛选:input type=“month”
<divclass="pc-filter-group"><labelclass="pc-label">月份</label><inputtype="month"id="filter-month"class="pc-input"></div>- 直接使用原生
<input type="month">控件:- 提供友好的年月选择器;
- 值通常为
YYYY-MM格式,便于和数据库中按月统计的逻辑对接;
id="filter-month"是后续 JS 逻辑读取条件的锚点,例如在加载列表时:
constmonthInput=document.getElementById('filter-month');if(monthInput){constmonthValue=monthInput.value;// 例如 2025-03// 根据 monthValue 计算起止日期,再从数据库筛选}3.2 类型筛选:收入 / 支出 / 全部
<divclass="pc-filter-group"><labelclass="pc-label">类型</label><selectid="filter-type"class="pc-input"><optionvalue="all">全部</option><optionvalue="income">收入</option><optionvalue="expense">支出</option></select></div>- 三个选项覆盖最常见的需求:只看收入、只看支出、看全部;
- 内部可以与
transactions表中的type字段一一对应; - 当用户点击“应用筛选”按钮时,JS 会读取这个值并在内存中的交易数组上做一次过滤或在数据库查询时带上条件。
3.3 “应用筛选”按钮
<buttonid="filter-apply"class="pc-button pc-button-primary">应用筛选</button>- 避免在每次选择筛选条件时立刻刷新列表,给用户一个“调整好再一次性应用”的缓冲;
- JS 端会在
PageManager的事件绑定中为这个按钮注册点击事件,触发列表刷新逻辑。
4. 表格结构:交易数据的承载容器
表格部分的结构比较标准:
<tableclass="pc-table"id="transactions-table"><thead><tr><th>日期</th><th>类型</th><th>账户</th><th>分类</th><th>金额</th><th>备注</th></tr></thead><tbody><!-- JS 动态渲染交易行 --></tbody></table>未来在loadTransactionsPage或类似方法中,会大致做这样的事情:
asyncloadTransactionsPage(){constmonthInput=document.getElementById('filter-month');consttypeSelect=document.getElementById('filter-type');constallTransactions=awaitwindow.financeDB.getAllTransactions();letfiltered=allTransactions;// 按月份过滤(示意)if(monthInput&&monthInput.value){const[year,month]=monthInput.value.split('-').map(v=>parseInt(v));constmonthStart=newDate(year,month-1,1);constmonthEnd=newDate(year,month,1);filtered=filtered.filter(t=>{constd=newDate(t.date);returnd>=monthStart&&d<monthEnd;});}// 按类型过滤if(typeSelect&&typeSelect.value!=='all'){filtered=filtered.filter(t=>t.type===typeSelect.value);}// 把 filtered 渲染到表格 tbody 中}上面代码是结合实际结构的合理推断,重点在于展示“过滤条件 → 内存数组过滤 → 渲染表格”的思路。
从 UI 的角度,这里有两点值得注意:
- 通过固定列顺序(日期、类型、账户、分类、金额、备注),让用户形成稳定的阅读习惯;
- 配合 CSS 的
pc-table样式,可以实现斑马纹行、高亮悬停、紧凑布局等视觉效果,提升可读性。
5. 与 ArkTS 的关系:完全由 Web 负责的展示层
交易列表页面的展示与过滤逻辑,完全运行在 Web 层和 IndexedDB 层:
- ArkTS 只负责提供 WebView 容器和底层插件;
- 交易数据从 IndexedDB 的
transactions表里读取; - 所有过滤和渲染都在 JS 中完成。
只有在以下场景,ArkTS 才会间接影响列表页面:
数据导入:
- ArkTS 插件从文件中读出历史交易 JSON 并交给 JS;
- JS 调用
financeDB.importData()将记录写入transactions表; - 交易列表页面刷新后即可看到新增的历史记录。
数据导出:
- 列表只是用来预览要导出的内容,导出动作本身由 FileManager 插件完成。
因此,这个模块在架构中的位置可以理解为:
- 它是“纯展示 + 轻逻辑”的前端模块;
- 不直接操作 ArkTS,只依赖 IndexedDB 提供的数据快照。
6. 小结:交易列表页面与过滤 UI 的设计要点
最后,总结本模块在 UI 设计和数据流上的几个关键点:
过滤栏与列表的清晰分区:
- 顶部
pc-filter-bar专门负责条件选择; - 下方
pc-card+ 表格负责展示结果,用户心智模型清晰。
- 顶部
使用原生控件简化交互:
input type="month"和select组件易于使用和实现;- 与后端数据结构(
YYYY-MM字符串、type字段)天然对齐。
表格列设计贴合财务语义:
- 日期、类型、账户、分类、金额、备注是最常用的几个维度;
- 这为后续扩展排序、导出选中行等功能打下基础。
过滤逻辑与 UI 解耦:
- UI 层只负责提供
id="filter-month"、id="filter-type"等输入点; - 具体过滤逻辑集中在
loadTransactionsPage或类似方法中,便于统一修改。
- UI 层只负责提供
与 ArkTS 松耦合:
- 列表展示完全在 Web 层完成,ArkTS 只在数据导入/导出场景出现;
- 这让前端可以自由优化 UI,而不必频繁涉及原生代码修改。
掌握了这个模块后,你就可以很自然地为系统增加更多过滤条件(例如账户、分类、多选时间范围),并在同一套 UI 框架下快速迭代交易列表的展示能力。
ArkTS 侧在交易列表中的角色
交易列表页面本身完全由 Web 层驱动,但它展示的数据会参与到 ArkTS 导入导出的“整体快照”中。容器和插件的注册同样发生在Index.ets中,示例如下:
import{MainPage,PluginEntry,}from'@magongshou/harmony-cordova/Index';import{FileManagerPlugin}from'../plugins/FileManagerPlugin';@Entry@Componentstruct Index{cordovaPlugs:Array<PluginEntry>=[{pluginName:'FileManager',pluginObject:newFileManagerPlugin()}];build(){// MainPage 会加载 index.html,进而加载 db.js 和 pages.js// 交易列表 UI、过滤逻辑和渲染,都在 pages.js 中完成MainPage({cordovaPlugs:this.cordovaPlugs});}}配合 FileManager 插件的导出/导入能力,交易列表中的每一行数据(对应transactions表中的一条记录)都会:
- 在导出时随其他表一起被打包进 JSON,由 ArkTS 写入备份文件;
- 在导入时从备份中恢复回来,再次通过
loadTransactionsPage渲染到列表中。
因此,ArkTS 虽然不直接参与交易列表的 UI 渲染,却通过“托管容器 + 数据搬运”保证了列表数据的长期可用性和可迁移性。