news 2026/3/26 17:17:04

HarmonyOS PC 焦点系统的正确建模方式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HarmonyOS PC 焦点系统的正确建模方式


子玥酱(掘金 / 知乎 / CSDN / 简书 同名)

大家好,我是子玥酱,一名长期深耕在一线的前端程序媛 👩‍💻。曾就职于多家知名互联网大厂,目前在某国企负责前端软件研发相关工作,主要聚焦于业务型系统的工程化建设与长期维护。

我持续输出和沉淀前端领域的实战经验,日常关注并分享的技术方向包括前端工程化、小程序、React / RN、Flutter、跨端方案
在复杂业务落地、组件抽象、性能优化以及多端协作方面积累了大量真实项目经验。

技术方向:前端 / 跨端 / 小程序 / 移动端工程化
内容平台:
掘金、知乎、CSDN、简书
创作特点:
实战导向、源码拆解、少空谈多落地
文章状态:
长期稳定更新,大量原创输出

我的内容主要围绕前端技术实战、真实业务踩坑总结、框架与方案选型思考、行业趋势解读展开。文章不会停留在“API 怎么用”,而是更关注为什么这么设计、在什么场景下容易踩坑、真实项目中如何取舍,希望能帮你在实际工作中少走弯路。

子玥酱 · 前端成长记录官 ✨
👋 如果你正在做前端,或准备长期走前端这条路
📚 关注我,第一时间获取前端行业趋势与实践总结
🎁 可领取11 类前端进阶学习资源(工程化 / 框架 / 跨端 / 面试 / 架构)
💡 一起把技术学“明白”,也用“到位”

持续写作,持续进阶。
愿我们都能在代码和生活里,走得更稳一点 🌱

文章目录

    • 引言
    • 一个必须先承认的事实
    • 焦点 ≠ 高亮
    • PC 焦点的本质:输入路由权
    • 高频坑:组件各自抢焦点
    • 正确思路:焦点必须集中建模
    • 一、定义一个明确的 FocusModel
    • 二、组件只声明“我能不能被聚焦”
    • 三、焦点切换由 Controller 统一调度
    • 四、键盘事件只看 FocusModel
      • 错误做法:组件自己处理键盘
      • 正确做法:集中分发
    • 五、Tab / 方向键:不是 UI 行为,而是焦点策略
      • 正确方式:焦点顺序也是模型
    • 六、多窗口场景:焦点必须绑定 Workspace
    • 为什么焦点问题这么“折磨人”?
    • 一个快速自检清单
    • 总结

引言

如果你已经把 HarmonyOS 应用做到 PC 形态,大概率迟早会遇到这些问题:

Tab 键乱跳,焦点有时消失,鼠标点了,键盘却没反应
多窗口一切换,输入全失效

第一反应通常是:

是不是系统焦点机制太复杂?

于是你开始:

  • 强行requestFocus
  • 到处打 log
  • 在组件生命周期里补焦点
  • 写一堆兜底逻辑

但越补越乱,因为真正的问题,并不在“焦点 API”。

一个必须先承认的事实

在 PC 场景下:

焦点不是 UI 状态,而是一种“交互所有权”。

而大多数项目,一开始就把它当成了:

“当前哪个组件高亮了”。

这一步,就已经走偏了。

焦点 ≠ 高亮

很多代码,焦点逻辑是这样写的:

@StateisFocused:boolean=falseonFocus(){this.isFocused=true}onBlur(){this.isFocused=false}

然后所有行为都基于这个状态判断。

问题在于:

  • 高亮只是表现,焦点却决定输入去向

当你把两者绑死时:

视觉没问题,交互已经乱了。

PC 焦点的本质:输入路由权

在 HarmonyOS PC 下,焦点至少决定三件事:

  1. 键盘事件发给谁
  2. 快捷键是否生效
  3. 输入法是否激活

但很多项目,焦点分散在各个组件里:

TextInput{onFocus(){/* ... */}}List{onFocus(){/* ... */}}

结果就是:

没有任何地方,知道“现在谁真正拥有输入”。

高频坑:组件各自抢焦点

你一定见过这种写法:

onClick(){this.requestFocus()}
onAppear(){this.requestFocus()}

短期看能解决问题,长期看是灾难:

  • 多个组件同时请求
  • 窗口切换时反复触发
  • 焦点状态不可预测

最终表现出来的就是:

焦点像在“漂移”。

正确思路:焦点必须集中建模

在 PC 项目中,有且只能有一个地方回答这个问题:

“当前输入属于谁?”

我们把它单独建模。

一、定义一个明确的 FocusModel

// pc/focus/FocusModel.tsexportclassFocusModel{privatefocusedId?:stringfocus(id:string){this.focusedId=id}blur(id:string){if(this.focusedId===id){this.focusedId=undefined}}isFocused(id:string):boolean{returnthis.focusedId===id}}

注意这里的关键点:

  • 焦点不是组件实例
  • 而是一个稳定的标识
  • UI 只是“注册者”

二、组件只声明“我能不能被聚焦”

// pc/focus/Focusable.tsexportinterfaceFocusable{id:stringcanFocus():boolean}
classEditorViewimplementsFocusable{id='editor'canFocus(){returntrue}}

组件不主动抢焦点,只声明能力。

三、焦点切换由 Controller 统一调度

// pc/focus/FocusController.tsexportclassFocusController{constructor(privatefocusModel:FocusModel){}requestFocus(target:Focusable){if(target.canFocus()){this.focusModel.focus(target.id)}}}

现在:

  • 点击
  • Tab
  • 窗口激活

全部走同一条路径。

四、键盘事件只看 FocusModel

这是最容易被忽略、但最关键的一步。

错误做法:组件自己处理键盘

onKeyDown(e){if(this.isFocused){handleKey(e)}}

正确做法:集中分发

functiononKeyDown(e){constfocusedId=focusModel.current()dispatchKeyEvent(focusedId,e)}
functiondispatchKeyEvent(id:string,e){consthandler=registry.get(id)handler?.onKey(e)}

焦点决定“谁接收”,不是“谁自己判断”。

五、Tab / 方向键:不是 UI 行为,而是焦点策略

很多项目会这样写:

onTab(){focusNext()}

问题是:

  • “下一个”是谁?
  • 顺序在哪里定义?
  • 不同窗口是否一致?

正确方式:焦点顺序也是模型

classFocusOrder{privateorder:string[]=[]next(current:string):string|undefined{constindex=this.order.indexOf(current)returnthis.order[index+1]}}
onTab(){constnext=focusOrder.next(focusModel.current())if(next)focusModel.focus(next)}

这样你才能:

  • 控制 Tab 行为
  • 做无障碍支持
  • 支持键盘优先模式

六、多窗口场景:焦点必须绑定 Workspace

在 PC 上,焦点不是全局唯一的

classWorkspaceFocus{workspaceId:stringfocusModel:FocusModel}

窗口切换时:

  • Workspace A 的焦点被冻结
  • Workspace B 的焦点恢复

否则你一定会遇到:

在 A 窗口打字,却改了 B 的内容。

为什么焦点问题这么“折磨人”?

因为:

  • 错乱立刻体现在输入上
  • 键盘问题比渲染更明显
  • 用户会直接觉得“不能用”

但根因往往是:

你从来没有一个地方,真正定义过“焦点是什么”。

一个快速自检清单

如果你的 HarmonyOS PC 项目:

  • 在组件里频繁requestFocus
  • 焦点状态分散在 UI State
  • 键盘事件由组件自己判断
  • Tab 行为写在页面逻辑里

那几乎可以确定:

焦点模型缺失。

总结

在 HarmonyOS PC 上,焦点不是一个 UI 技巧,而是一种输入资源的分配机制。

  • 模型不集中,焦点必乱
  • 焦点不稳定,交互必崩
  • 焦点一乱,多输入全废
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/22 10:00:34

【金融项目实战】4_金融项目 _测试流程

文章目录一、项目测试流程1.1 UI功能测试1.2 接口测试二、测试步骤2.1 需求评审2.2 测试计划2.2.1 测试对象2.2.2 测试准则2.2.3 风险来源2.2.4 人员安排2.2.5 测试实施2.3 设计用例2.4 执行用例2.5 缺陷管理2.5.1 提交方式2.5.2 面试题2.6 测试报告一、项目测试流程 1、需求评…

作者头像 李华
网站建设 2026/3/13 3:40:34

lsblk是什么linux命令

slblk 不是标准的 Linux 命令。您可能是指以下命令之一: 可能的拼写混淆 表格 复制 命令全称功能描述lsblkList Block Devices最可能的意图 - 列出所有块设备(硬盘、分区、USB 等)blkidBlock ID显示块设备的 UUID、文件系统类型等信息blo…

作者头像 李华
网站建设 2026/3/13 2:27:46

lsblk -a磁盘上的新空间如何扩容加到磁盘上

场景一:虚拟机/云服务器磁盘扩容(最常见) 1. 确认新空间已识别 bash 复制 lsblk -a # 或查看详细容量变化 lsblk -fb 2. 扩容分区(以 /dev/sda 为例,假设根分区是 /dev/sda3) 方法 A:使用…

作者头像 李华
网站建设 2026/3/26 1:42:37

<span class=“js_title_inner“>AI 基础概念全景指南</span>

📖 写在前面人工智能(AI)正在重塑我们的世界。从 ChatGPT 到自动驾驶,从医疗诊断到艺术创作,AI 无处不在。但对于初学者来说,AI 领域充满了复杂的概念:机器学习、深度学习、神经网络、Transform…

作者头像 李华
网站建设 2026/3/19 13:15:02

这篇一次讲透!MWORKS 2026a亮点全集

发布概览 历经五年持续的工程实践与打磨,CPS一体化平台已经成型。全新发布的MWORKS 2026a 实现从“功能可替代”到“工程可承载”的跃迁,3大基础环境焕新升级、21个产品大幅更新,新增6个工具箱 / 模型库,合计达40个工具箱含5600函…

作者头像 李华
网站建设 2026/3/13 22:46:53

建议收藏!大模型核心概念全面解析,程序员小白入门必备

想转AI产品经理,但一看术语就头大,什么Token、Embedding、RLHF、Temperature……这都是啥? 说实话,这些词确实唬人。培训机构恨不得每个概念单独开一门课卖你钱,技术文章又写得跟论文似的,看完更懵。今天老…

作者头像 李华