新闻详情

新闻详情

首页 / 资讯中心 / 详情

Compose for Web 事件处理详解:从 attrs 事件监听器到 addEventListener 的完整机制

发布时间:2026/9/13 18:54:46来源:尧图网络
Compose for Web 事件处理详解:从 attrs 事件监听器到 addEventListener 的完整机制
Compose for Web 事件处理详解从 attrs 事件监听器到 addEventListener 的完整机制【免费下载链接】compose-multiplatformCompose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.项目地址: https://gitcode.com/GitHub_Trending/co/compose-multiplatform本篇指南聚焦 Compose Multiplatform 的 HTML 目标Compose for Web中的事件处理机制。读完本文你将掌握如何在attrs块中通过onClick、onInput等专用函数注册事件监听器、如何使用addEventListener处理框架未提供专用函数的事件、如何访问合成事件对象SyntheticEvent及其子类上的原生属性并调用preventDefault()同时理解这些事件在重组合recomposition过程中是如何被注册与卸载的底层实现。事件如何附加到 DOM 元素AttrsScope 与 EventsListenerScope在 Compose for Web 中所有 DOM 元素Button、TextArea、Div……都接受一个可选的attrs构建块。attrs的接收者是AttrsScopeTElement而事件能力正来自它继承的EventsListenerScope// html/core/src/jsMain/kotlin/org/jetbrains/compose/web/attributes/AttrsScope.kt interface AttrsScopeout TElement : Element : EventsListenerScope { ... }见 AttrsScope.kt。AttrsScope同时负责三件事设置属性attr、内联样式style和事件监听继承自EventsListenerScope的全部onXxx函数。其实现类AttrsScopeBuilder内部持有一个EventsListenerScopeBuilder并通过委托把registerEventListener等方法转发过去见 AttrsScope.kt。EventsListenerScope的核心设计是注册表模式每个onXxx函数并不直接调用element.addEventListener而是通过registerEventListener把一个SyntheticEventListener加入列表由运行时统一处理挂载这一点对理解重组合行为很关键见下文事件注册与卸载的底层机制// html/core/src/jsMain/kotlin/org/jetbrains/compose/web/attributes/EventsListenerScope.kt interface EventsListenerScope { ComposeWebInternalApi fun registerEventListener(listener: SyntheticEventListener*) fun onClick(listener: SyntheticMouseEventListener) { registerEventListener(MouseEventListener(CLICK, listener)) } // ... }见 EventsListenerScope.kt。onClick鼠标事件与 SyntheticMouseEvent在attrs块中为Button添加点击监听器的标准写法如下Button( attrs { onClick { event - // event is of SyntheticMouseEvent type println(button clicked at ${event.movementX}, ${event.movementY}) val nativeEvent event.nativeEvent // 浏览器原生的 MouseEvent } } ) { Text(Button) }event的类型是SyntheticMouseEvent它继承自SyntheticEventEventTarget并在构造时把原生MouseEvent的关键字段快照为 Kotlin 属性altKey、button、buttons、clientX/clientY、ctrlKey、metaKey、offsetX/offsetY、pageX/pageY、screenX/screenY、shiftKey、x/y等并提供getModifierState(keyArg)方法。定义见 SyntheticMouseEvent.kt。源码中有两个值得注意的细节movementX/movementY的 Safari 兼容处理。由于 SafariMobile 的MouseEvent上这两个字段可能为undefined实现里做了空值兜底为0对应问题单 CMP-5304// html/core/src/jsMain/kotlin/org/jetbrains/compose/web/events/SyntheticMouseEvent.kt val movementX: Int (nativeEvent.asDynamic().movementX as? Int) ?: 0 val movementY: Int (nativeEvent.asDynamic().movementY as? Int) ?: 0见 SyntheticMouseEvent.kt。同一文件还定义了SyntheticWheelEvent增加deltaX/deltaY/deltaZ/deltaMode配合onWheel使用和SyntheticDragEvent增加dataTransfer二者都继承自SyntheticMouseEvent因此滚轮/拖拽事件也能读取鼠标坐标字段。见 SyntheticMouseEvent.kt。onInput受控输入与状态同步TextArea等输入元素通过onInput把用户输入同步进 Compose 状态构成受控组件val text remember { mutableStateOf() } TextArea( value text.value, attrs { onInput { text.value it.value } } )这里的it是SyntheticInputEventValueType, HTMLInputElement。它除了继承全部SyntheticEvent属性外还额外提供value由InputType解析出的当前输入值泛型ValueType文本输入下即Stringdata、dataTransfer、inputType浏览器InputEvent的字段源码通过asDynamic()提取因为实际收到的事件可能只是普通EventisComposing输入法组合中标志默认false。见 SyntheticInputEvent.kt。onInput本身的实现位于InputAttrsScope它通过InputEventListener注册InputType决定了如何从原生事件中提取value文本、数字、复选框布尔值等。同作用域还提供了onChange、onBeforeInput、onSelect、onInvalid四个输入相关事件见 InputAttrsScope.kt。状态写回text.value后会触发重组TextArea(value text.value, ...)随更新形成输入 → 状态 → 重渲染的闭环。addEventListener处理没有专用函数的事件对于EventsListenerScope未提供专用配置函数的事件如submit、reset、select可以直接调用addEventListener传入事件名与监听器。以下示例定义了一个Form在触发submit事件时的行为并调用preventDefault()阻止浏览器默认的表单提交导航Form(attrs { this.addEventListener(submit) { console.log(Hello, Submit!) it.preventDefault() } })addEventListener有两个重载最终都通过SyntheticEventListener(eventName, listener)注册见 EventsListenerScope.ktfun T : SyntheticEventout EventTarget addEventListener( eventName: String, listener: (T) - Unit ) fun addEventListener( eventName: String, listener: (SyntheticEventEventTarget) - Unit )两点补充源码注释说明options参数as of now this param is always equal to Options.DEFAULT即当前 API 签名中没有暴露监听选项行为与标准 DOMaddEventListener的默认模式一致所有可用作事件名字符串的常量都集中在EventsListenerScope的 companion 对象中CLICK click、INPUT input、CHANGE change、SUBMIT submit、RESET reset、BEFOREINPUT beforeinput、INVALID invalid等见 EventsListenerScope.kt注册时可直接使用这些常量。开箱即支持的事件处理函数一览EventsListenerScope接口为以下事件提供了类型安全的专用函数完整清单与源码一致EventsListenerScope.kt类别函数事件名常量事件对象类型鼠标onContextMenuonClickonDoubleClickonMouseDownonMouseUponMouseEnteronMouseLeaveonMouseMoveonMouseOutonMouseOvercontextmenuclickdblclickmousedownmouseupmouseentermouseleavemousemovemouseoutmouseoverSyntheticMouseEvent滚轮onWheelwheelSyntheticWheelEvent拖拽onDragonDroponDragStartonDragEndonDragOveronDragEnteronDragLeavedragdropdragstartdragenddragoverdragenterdragleaveSyntheticDragEvent剪贴板onCopyonCutonPastecopycutpasteSyntheticClipboardEvent键盘onKeyDownonKeyUpkeydownkeyupSyntheticKeyboardEvent焦点onFocusonBluronFocusInonFocusOutfocusblurfocusinfocusoutSyntheticFocusEvent触摸onTouchCancelonTouchMoveonTouchEndonTouchStarttouchcanceltouchmovetouchendtouchstartSyntheticTouchEvent动画onAnimationEndonAnimationIterationonAnimationStartanimationendanimationiterationanimationstartSyntheticAnimationEvent滚动onScrollscrollSyntheticEventEventTarget任意事件addEventListener(eventName, listener)任意字符串由泛型决定事件注册与卸载的底层机制理解 Compose for Web 事件系统的关键是看SyntheticEventListener如何桥接 Kotlin 与浏览器原生 DOM。桥接层SyntheticEventListenerSyntheticEventListener实现了 JS 的EventListener接口同时实现NamedEventListener暴露事件名name其handleEvent把原生Event包装成对应的合成事件后交给用户回调// html/core/src/jsMain/kotlin/org/jetbrains/compose/web/attributes/SyntheticEventListener.kt open class SyntheticEventListenerT : SyntheticEvent* internal constructor( val event: String, val listener: (T) - Unit ) : EventListener, NamedEventListener { override val name: String event override fun handleEvent(event: Event) { listener(SyntheticEventEventTarget(event).unsafeCastT()) } }见 SyntheticEventListener.kt 与 DomApplier.kt。各事件类型的子监听器MouseEventListener、KeyboardEventListener、FocusEventListener、TouchEventListener、DragEventListener、ClipboardEventListener、AnimationEventListener、InputEventListener、ChangeEventListener、SelectEventListener覆写handleEvent把原生事件强制转换为对应类型如MouseEvent、KeyboardEvent后构造类型化的合成事件InputEventListener/ChangeEventListener则额外通过inputType.inputValue(event)解析出输入值。见 SyntheticEventListener.kt。挂载与差量更新DomElementWrapper合成事件基类SyntheticEvent在构造时快照了nativeEvent的核心字段并暴露了与原生事件对齐的控制方法// html/core/src/jsMain/kotlin/org/jetbrains/compose/web/events/SyntheticEvent.kt open class SyntheticEventElement : EventTarget internal constructor( val nativeEvent: Event ) { val target: Element nativeEvent.target.unsafeCastElement() val bubbles: Boolean nativeEvent.bubbles val cancelable: Boolean nativeEvent.cancelable // ... fun preventDefault(): Unit nativeEvent.preventDefault() fun stopPropagation(): Unit nativeEvent.stopPropagation() fun stopImmediatePropagation(): Unit nativeEvent.stopImmediatePropagation() fun composedPath(): ArrayEventTarget nativeEvent.composedPath() }见 SyntheticEvent.kt。preventDefault()、stopPropagation()都只是对原生事件方法的直接委托因此在attrs事件回调中调用它们与标准 Web 行为一致。真正与 DOM 打交道的代码在DomElementWrapper。元素节点持有当前监听器列表每次attrs块重新执行重组后运行时用先全部移除、再全部添加的方式刷新监听器// html/core/src/jsMain/kotlin/org/jetbrains/compose/web/dom/Base.kt fun updateEventListeners(list: ListNamedEventListener) { currentListeners.forEach { node.removeEventListener(it.name, it) } currentListeners list currentListeners.forEach { node.addEventListener(it.name, it) } }见 Base.kt。从源码结构看这意味着事件监听器的真值永远来自最近一次attrs构建块的执行结果旧的匿名闭包会在下一轮重组中被解绑——这与 Compose UI 是函数、每次重组重建描述的模型一致也解释了为什么不需要手动removeEventListener只要把onClick { ... }从attrs块中移除该监听器就会在下次刷新时从节点上被卸载。完整可运行示例将上述能力组合起来下面是一个完整的main入口一个输出鼠标坐标的按钮以及一个把输入内容实时同步到Span显示区的最小受控输入。完整示例与官方教程一致tutorials/HTML/Events_Handling/README.mdimport androidx.compose.runtime.* import org.jetbrains.compose.web.css.* import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.renderComposable fun main() { renderComposable(rootElementId root) { Button( attrs { onClick { event - println(button clicked at ${event.movementX}, ${event.movementY}) } } ) { Text(Button) } val text remember { mutableStateOf() } TextArea( value text.value, attrs { onInput { text.value it.value } } ) Span { Text(Typed text ${text.value}) } } }运行前提该示例面向 HTML 目标需使用 Compose for Web 的 Gradle 插件org.jetbrains.compose.web构建 JS 产物并把渲染容器root元素挂到页面的index.html中参考仓库 examples/html/compose-in-js 这类最小 HTML 工程结构。小结与注意事项attrs块是 Compose for Web 中事件、属性、样式的统一入口事件能力由AttrsScope继承的EventsListenerScope提供。常用事件用类型安全的onXxx函数回调参数是带类型快照的SyntheticXxxEvent其余事件用addEventListener(name) { ... }回调参数是通用的SyntheticEvent。合成事件对象上可直接调用preventDefault()、stopPropagation()也可通过nativeEvent取回浏览器原生事件做进一步操作。监听器无需手动解绑每次重组后运行时会基于attrs块的最新执行结果刷新元素上的监听器集合Base.kt。跨端注意movementX/movementY在部分移动端 Safari 上不可用框架已兜底为0ANIMATIONCANCEL常量标注仅 Firefox 与 Safari 支持见 EventsListenerScope.kt。【免费下载链接】compose-multiplatformCompose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.项目地址: https://gitcode.com/GitHub_Trending/co/compose-multiplatform创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Lexical 团队数据自动化生成指南:从 GitHub 贡献者数据到 team.json 的完整流程 2026/9/13 19:24:48

Lexical 团队数据自动化生成指南:从 GitHub 贡献者数据到 team.json 的完整流程

Lexical 团队数据自动化生成指南:从 GitHub 贡献者数据到 team.json 的完整流程 【免费下载链接】lexical Lexical is an extensible text editor framework that provides excellent reliability, accessibility and performance. 项目地址: https://gitcode.com…

阅读更多 →
Open SWE:开源编程助手框架解析与应用实践 2026/9/13 19:24:48

Open SWE:开源编程助手框架解析与应用实践

1. Open SWE项目概述:复刻顶级科技公司的内部编程助手Open SWE是LangChain团队基于Deep Agents和LangGraph构建的开源框架,专门用于创建企业内部编程助手。这个项目复刻了Stripe、Coinbase等顶尖科技公司内部工具的核心架构模式,包括隔离云沙…

阅读更多 →
jcode 跨机器远程控制实战:WebSocket 网关的配对、远程会话驱动与排障 2026/9/13 19:24:48

jcode 跨机器远程控制实战:WebSocket 网关的配对、远程会话驱动与排障

jcode 跨机器远程控制实战:WebSocket 网关的配对、远程会话驱动与排障 【免费下载链接】jcode The most RAM efficient harness 项目地址: https://gitcode.com/GitHub_Trending/jcod/jcode 本篇指南基于 jcode 仓库中的 远程脚本说明文档 展开,讲…

阅读更多 →
yfinance 如何设置 locale 让 Ticker.info 返回本地语言的公司名称 2026/9/13 19:24:47

yfinance 如何设置 locale 让 Ticker.info 返回本地语言的公司名称

yfinance 如何设置 locale 让 Ticker.info 返回本地语言的公司名称 【免费下载链接】yfinance Download market data from Yahoo! Finances API 项目地址: https://gitcode.com/GitHub_Trending/yf/yfinance 用 yfinance 拉取股票资料时,Ticker.info 默认返回…

阅读更多 →
TRL 训练加速实战指南:vLLM 快速生成、优化注意力、Liger Kernel 与混合精度 2026/9/13 19:24:47

TRL 训练加速实战指南:vLLM 快速生成、优化注意力、Liger Kernel 与混合精度

TRL 训练加速实战指南:vLLM 快速生成、优化注意力、Liger Kernel 与混合精度 【免费下载链接】trl Train transformer language models with reinforcement learning. 项目地址: https://gitcode.com/GitHub_Trending/tr/trl 本篇指南基于 TRL 官方文档 spee…

阅读更多 →
CANoe与CAPL在HiL测试中的核心职责与自动化实战解析 2026/9/13 19:21:47

CANoe与CAPL在HiL测试中的核心职责与自动化实战解析

在汽车测试这个圈子里混久了你会发现一个很有意思的现象:岗位JD里几乎都会写“熟悉CANoe、会CAPL优先”,面试时也总被问“你在HiL测试里怎么用CANoe的”。很多新人会困惑:CANoe不就是个看报文的工具吗?CAPL到底要会到什么程度才算…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞