山海万灵 HarmonyOS 文化知识设计续篇(14):2in1 设备键鼠交互补齐方案
在 2in1 宽屏窗口里,触摸、鼠标和键盘会交替出现。山海万灵的卡片、筛选和详情入口需要把“看见焦点”“暂时悬停”“真正选中”分开处理,才能让鼠标点击、Enter 和 Space 进入同一条业务命令。本篇给出键鼠交互补齐的设计方案,范围覆盖输入状态、焦点顺序、统一激活和窗口变化后的恢复。
一、先确定交互边界
方案服务于首页、图鉴、探索、馆长和“我的”中的可操作元素:一级导航、筛选项、神兽卡片、推荐卡片、详情中的继续探索动作,以及设置项。触摸手势、既有视觉主题和五个一级导航保持原状;本轮不引入新的业务流程,也不把宽屏适配等同于键鼠能力。
鼠标悬停只提供短暂视觉反馈,键盘焦点只服务于可访问性和键盘操作,业务选中态才决定详情、筛选结果或探索目标。三种状态混用时,鼠标移出可能错误清掉业务选择,窗口切换也会让焦点回落到不可操作位置。
二、把输入状态显式建模
type InputMode = 'touch' | 'mouse' | 'keyboard'
interface FocusState {
inputMode: InputMode
focusedId: string
hoveredId: string
selectedId: string
}
interface ActivationRequest {
id: string
source: 'click' | 'keyboard'
}
focusedId、hoveredId 与 selectedId 分别保存焦点、悬停和业务选择。页面切换、数据刷新或尺寸变化时,只恢复仍然存在且可用的焦点目标;找不到目标时,回退到所属区域第一个可操作控件。
三、统一鼠标与键盘的激活入口
卡片点击与键盘确认不应各自维护导航、发现或统计更新逻辑。组件负责把输入转换为 ActivationRequest,领域命令负责完成一次动作,页面只接收结果并刷新选择、提示和进度。这样可以让后续的新增输入设备继续复用同一条链路。
function onCardKey(event: KeyEvent, id: string): void {
if (event.keyCode === KEY_ENTER || event.keyCode === KEY_SPACE) {
activate({ id, source: 'keyboard' })
}
}
async function activate(request: ActivationRequest): Promise<void> {
if (!isEnabled(request.id)) return
const result = await appViewModel.dispatch(request)
viewState.selectedId = request.id
notice = result.notice
}
四、键鼠设计链路
下图将输入事件、统一激活、业务状态与可恢复反馈拆开。卡片不再直接根据输入设备修改业务状态;同一个激活命令可以在点击和键盘确认之间复用,禁用项和已卸载目标则进入明确的降级路径。

五、焦点顺序与视觉顺序一致
页面按“一级导航 → 页内筛选 → 主列表或主要内容 → 辅助操作”的阅读路径建立焦点顺序。Tab 前进、Shift+Tab 回退;卡片列表在需要时使用方向键完成同层移动;Escape 返回上级区域或关闭轻量弹层。焦点环应独立于选中背景,深浅色主题分别校验对比度,避免只靠透明度造成不可见反馈。
| 场景 | 风险 | 设计处理 |
|---|---|---|
| 焦点顺序与视觉顺序不一致 | 键盘用户失去位置感 | 建立显式顺序并在页面评审中逐项核对 |
| 悬停色在深色模式不明显 | 鼠标目标不可辨识 | 为 hover 与 focus 分别定义对比度和边框规则 |
| 禁用控件仍可聚焦 | 确认键触发无效动作 | 禁用同时影响可聚焦性和激活入口 |
| 宽窄窗口切换卸载目标 | 焦点丢失 | 回退到所属区域首个可操作元素 |
六、失败与降级路径
输入设备暂不可用、目标项被刷新移除、动作被权限或业务条件拒绝时,页面保留已选业务内容,不把临时 hover 当成选中结果。焦点回退后给出可读提示;重复确认不重复累计发现或印章;无可用目标时将焦点停在页内说明区域,并提供返回或重试入口。
function recoverFocus(previousId: string, candidates: string[]): string {
if (candidates.includes(previousId)) return previousId
return candidates.find(isEnabled) ?? ''
}
function onTargetRemoved(previousId: string): void {
viewState.focusedId = recoverFocus(previousId, visibleActionIds())
hoverState.clear()
}
七、实施顺序
- 盘点五个一级页面的可操作元素和视觉阅读顺序。
- 为共用卡片补齐 hover、focus、disabled、selected 四套状态契约。
- 接入统一激活命令,再将点击、Enter 与 Space 接到同一入口。
- 为 Tab、方向键和 Escape 建立页面级规则。
- 在 2in1 或桌面窗口环境进行输入切换与窗口缩放回归。
八、验收清单
- 鼠标悬停不会修改业务选中态。
- Tab 顺序与视觉阅读顺序一致,Shift+Tab 能稳定回退。
- Enter、Space 与点击复用同一业务命令。
- 禁用控件不会获得可激活焦点。
- 窄窗与宽窗切换后焦点能恢复到可操作目标。
- 深浅色主题下的焦点环和悬停态均可辨识。
九、后续验证计划
落地后以键盘事件与 hover/focus 处理代码、2in1 或桌面窗口操作录屏、Tab 顺序与 Enter 激活日志、窗口切换后的焦点恢复画面为验收证据,并完成 HarmonyOS 构建和正式包运行复核。相关能力以实际交互结果为准。
更多推荐
所有评论(0)