New Expensify交互设计原则:无缝金融协作体验的构建基石
New Expensify作为新一代金融协作平台,以聊天为中心重新构想了财务交互体验。其交互设计遵循一系列核心原则,确保跨平台一致性、离线可用性和用户操作的直观性。本文将深入解析这些设计原则及其在实际开发中的应用。
跨平台一致性原则
New Expensify支持Web、移动Web、桌面端、iOS和Android五大平台,交互设计的首要原则是实现99.9999%的跨平台一致性。这意味着用户在任何设备上都能获得几乎相同的体验和功能支持。
全平台功能对等
根据跨平台设计哲学,任何功能必须在所有支持平台上实现才算完成。开发团队采用"一次设计,多端适配"的策略,避免平台特定功能导致的用户体验碎片化。例如,聊天功能在移动设备上的消息输入框与桌面端保持一致的交互逻辑,确保用户切换设备时无需重新学习操作方式。
平台特定代码隔离
为实现跨平台一致性,项目严格规定平台相关代码必须放在专用文件和文件夹中。开发人员使用特定的文件扩展名区分不同平台的实现:
- 移动端:
index.native.js - iOS/Android原生:
index.ios.js/index.android.js - Web端:
index.website.js - 桌面端:
index.desktop.js
这种隔离机制确保业务逻辑与平台适配代码分离,如src/components/OfflineWithFeedback.tsx组件在不同平台上的渲染逻辑被封装在独立文件中,保证了核心交互逻辑的统一。
数据流驱动的交互模式
New Expensify采用单向数据流架构,所有UI交互都遵循"数据变更→视图更新"的响应式模式,确保用户操作的可预测性和系统状态的一致性。
数据流闭环
应用中的数据流动遵循严格的六步闭环:
- 服务器推送数据到客户端磁盘
- 磁盘数据更新到UI
- UI展示数据给用户
- 用户在UI输入数据
- UI将数据提交到服务器
- 服务器处理后开始新一轮循环
这种设计确保用户操作与系统状态始终保持同步。例如,当用户在聊天中发送消息时,数据首先写入本地存储并立即更新UI,然后异步提交到服务器,实现"操作即所见"的即时反馈体验。
非阻塞UI设计
根据数据绑定哲学,UI组件必须并行调用所有异步操作,不得等待一个API调用完成后再发起另一个。这意味着界面渲染永远不会被网络请求阻塞,用户始终可以与应用交互。例如,src/pages/home/ReportScreen.tsx在加载聊天历史的同时,会并行请求用户头像、附件预览等数据,最大限度减少等待时间。
离线优先的用户体验
针对金融协作场景,New Expensify特别优化了离线状态下的交互体验,让用户在网络不稳定或完全离线时仍能完成关键操作。
四种离线交互模式
开发团队定义了四种离线UX模式,覆盖不同使用场景:
A. 无反馈乐观更新模式
适用于成功率极高且结果可预测的操作,如固定聊天对话。用户点击固定按钮后,UI立即更新(对话移至顶部,按钮状态变化),无需等待服务器确认。实现代码见src/actions/ReportActions.ts中的togglePinnedState方法,通过API.write()设置乐观更新数据。
B. 带反馈乐观更新模式
用于需要让用户知道操作待处理状态的场景,如发送聊天消息。离线时,消息显示灰色(50%透明度)并标记"待发送"状态。相关实现见src/components/Message/Message.tsx,通过<OfflineWithFeedback>组件包裹内容实现状态展示。
C. 表单阻塞模式
适用于需要服务器验证的表单提交,如邀请团队成员。离线时,提交按钮置灰并显示"当前离线"提示,但允许用户继续填写表单,数据会保存在本地,待网络恢复后自动提交。实现见src/components/FormAlertWithSubmitButton.tsx组件。
D. 全屏阻塞模式
仅用于极端情况,如获取银行账户列表等必须实时数据的场景。此时整个页面会显示加载状态,防止用户看到过时信息。实现见src/components/FullPageOfflineBlockingView.tsx。
离线状态检测与处理
应用通过src/libs/NetworkConnection.ts实时监测网络状态,并通过src/hooks/useNetworkStatus.ts向组件提供网络状态信息。UI组件根据网络状态自动调整交互模式,如src/pages/settings/Payments/PaymentMethodsPage.tsx在离线时会切换为只读模式,防止用户进行无法完成的支付操作。
异步操作的并行优化
为提升交互响应速度,New Expensify采用并行异步调用策略,确保UI始终保持流畅。
异步操作处理原则
根据异步代码哲学,应用遵循以下规则处理异步操作:
- 并行执行独立操作:使用
Promise.all()同时发起多个独立API请求,如同时获取用户信息和权限数据
const [user, permissions] = await Promise.all([
getUser(),
getPermissions(),
]);
-
优先使用async/await:相比
.then/.catch链式调用,async/await语法使异步逻辑更易读 -
UI层异步调用并行化:组件应同时发起所有必要的API请求,不等待前一个请求完成
这些原则在src/pages/Dashboard/DashboardPage.tsx中得到充分体现,页面加载时同时请求交易数据、通知列表和账户余额,显著减少了页面准备时间。
异步错误处理
应用采用优雅的错误处理机制,当异步操作失败时,通过OfflineWithFeedback组件向用户展示错误状态并提供重试选项。例如,发送失败的消息会显示错误图标,用户点击即可重新发送,无需重新输入内容。
国际化与本地化交互
New Expensify面向全球用户,交互设计充分考虑多语言和区域差异,确保不同文化背景的用户都能顺畅使用。
全量本地化支持
根据国际化哲学,所有用户可见内容必须支持本地化,包括:
- 文本翻译:使用useLocalize hook
- 日期时间:通过DateUtils处理
- 数字金额:使用NumberFormatUtils格式化
- 电话号码:通过LocalePhoneNumber处理
智能 plural 处理
应用支持复杂的复数规则,满足不同语言的语法要求。翻译文件中使用对象形式定义不同数量的文本:
messages: () => ({
zero: 'No messages',
one: 'One message',
other: ({count}) => `${count} messages`,
})
这种处理方式确保在任何语言环境下,数字与文本的搭配都符合语法规则,如阿拉伯语中的双数形式或俄语中的特殊复数规则。
交互设计原则的实际应用
这些设计原则不是纸上谈兵,而是贯穿于代码库的每个角落。开发团队通过一系列工具和组件确保原则的落地实施:
核心交互组件库
- src/components/目录包含所有基础交互组件
- src/hooks/提供交互状态管理钩子
- src/libs/API.ts封装网络请求,实现乐观更新
- src/actions/目录包含所有用户操作的业务逻辑
开发规范与检查工具
项目通过ESLint规则和PR审查流程确保交互设计原则得到遵守:
- .eslintrc.js中定义了禁止平台特定代码混写的规则
- PR_REVIEW_GUIDELINES.md要求审查者确认新功能符合跨平台和离线设计原则
结语
New Expensify的交互设计原则围绕"用户中心、场景驱动"构建,通过跨平台一致性、数据流驱动、离线优先等设计理念,打造了适应金融协作场景的直观交互体验。这些原则不仅指导着当前的产品开发,也为未来功能扩展提供了设计框架。
开发团队欢迎社区贡献者通过CONTRIBUTING.md参与交互体验的优化,共同打造下一代金融协作平台。所有设计决策和实现细节都记录在contributingGuides/philosophies/目录下,供开发者查阅和遵循。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考





