事件处理
原生 ArkUI 事件会先进入 EventSink,再转成 Dioxus 事件按顺序派发。点击、变更这类离散事件不会悄悄丢掉;高频的 pointer move 可以在进 VirtualDom 前按节点合并。
事件与 Payload
| 事件 | Payload | 用途 |
|---|---|---|
onclick / on_press |
ClickData |
点击 |
onlongpress |
ClickData |
原生长按 |
onchange / oninput / ontoggle |
ChangeData |
输入与选择 |
onsubmit |
SubmitData |
文本提交 |
onscroll |
ScrollData |
滚动 offset |
onswiperchange |
SwiperChangeData |
Swiper 页码 |
onrefresh |
RefreshData |
下拉刷新 |
onarea / onlayout |
AreaData |
布局区域 |
onhover |
HoverData |
hover 状态 |
onfocus / onblur |
FocusData |
焦点 |
onfocusin / onfocusout |
FocusData |
子树内的焦点变化,会冒泡 |
onkey / onkeypreime |
KeyData |
物理按键、修饰键、按键阶段 |
onmouse |
MouseData |
鼠标按键、移动、目标边界 |
onaxis |
AxisData |
滚轮与触摸板轴增量 |
| drag/touch/move | PointerData |
坐标、阶段、设备 |
事件使用紧凑名称,例如 onchange、onreachend。历史 snake_case 名称不再注册。
键盘与弹层
窗口断点仅选择布局,不关闭键盘、鼠标或触摸能力。原生按键仅入队一次,再由 Dioxus 沿逻辑树冒泡。
key_capture: "enter space escape" 声明由控件接管的按键,renderer 在原生回调阶段阻止对应的默认行为。文本编辑器应只接管需要的键;Terminal 使用 onkeypreime 与 key_capture: "all",避免同一物理按键再进入 IME。
focus_scope: true 在挂载时迁入焦点,在移除时返回仍然有效的触发器;focus_trap: true 限制 Tab/Shift+Tab。列表可以用 focus_navigation: "vertical" 或 "horizontal"。axis_capture: true 阻止滚轮继续滚动祖先容器。
更新状态
let mut value = use_signal(String::new);
rsx! {
textinput {
value: value(),
placeholder: "请输入",
onchange: move |event| value.set(event.string_value.clone()),
}
}
事件闭包通常捕获可复制的 Signal handle。回调应更新状态或派发领域命令,不直接保留 event 内部借用。
冒泡
浮层 panel 可阻止点击继续到 backdrop:
column {
onclick: move |event| event.stop_propagation(),
text { "弹层内容" }
}
只在组件确实拥有事件边界时停止传播;大面积容器无条件拦截会破坏上层手势和无障碍行为。
长按与默认行为
onlongpress 使用 ArkUI LongPress Gesture,默认单指保持约 500ms 后在 Accept 阶段派发一次。它不是延迟 click,普通点击不会触发长按 handler。
Native callback 边界
不在 Dioxus event dispatch 内触发的原生回调可能发生在 tree patch 中。此时用当前 root 的 RuntimeHandle 把状态更新排到下一 UI tick,避免重入 render:
let runtime = use_runtime_handle();
let mut title = use_signal(String::new);
let callback = move |next: String| {
runtime.queue_ui(move || title.set(next));
};