Dioxus框架中(Event Handler)

269 阅读3分钟

在下面使用日志 r

log = "0.4" env_logger = "0.9"

Event Handlers

Event handler用于响应用户操作。例如,当用户点击、滚动、移动鼠标或输入字符时,可能会event handler。

Event handler附加到元素上。例如,我们通常不关心应用程序内发生的所有点击,只关心特定按钮上的点击。

Event handler类似于常规属性,但它们的名称通常以on开头,并接受闭包作为值。当它监听的事件被触发时,闭包将被调用,并传递该事件。

例如,要处理元素上的点击,我们可以指定一个onclick处理器:

rsx! {
    button { onclick: move |event| log::info!("Clicked! Event: {event:?}"), "click me!" }
}

Event对象

Event handler接收一个包含有关event信息的Event对象。不同类型的事件包含不同类型的数据。例如,与鼠标相关的事件包含MouseData,它告诉你鼠标点击的位置以及使用了哪些鼠标按钮。

在上面的例子中,这个事件数据被记录到了终端:

Clicked! Event: UiEvent { bubble_state: Cell { value: true }, data: MouseData { coordinates: Coordinates { screen: (242.0, 256.0), client: (26.0, 17.0), element: (16.0, 7.0), page: (26.0, 17.0) }, modifiers: (empty), held_buttons: EnumSet(), trigger_button: Some(Primary) } }
Clicked! Event: UiEvent { bubble_state: Cell { value: true }, data: MouseData { coordinates: Coordinates { screen: (242.0, 256.0), client: (26.0, 17.0), element: (16.0, 7.0), page: (26.0, 17.0) }, modifiers: (empty), held_buttons: EnumSet(), trigger_button: Some(Primary) } }

要了解HTML提供的不同类型的事件类型,请参阅事件模块文档。

Event传播

有些事件会首先在事件起源的元素上触发,然后向上传播。例如,在div内的button上的点击事件会首先触发按钮的事件监听器,然后是div的事件监听器。

关于事件传播的更多信息,请参阅mdn文档中的事件冒泡

如果你想阻止这种行为,可以在事件上调用stop_propagation()

rsx! {
    div { onclick: move |_event| {},
        "outer"
        button {
            onclick: move |event| {
                event.stop_propagation();
            },
            "inner"
        }
    }
}

防止默认行为

有些事件有默认行为。对于键盘事件,这可能是输入字符。对于鼠标事件,这可能是选择文本。

在某些情况下,你可能想要避免这种默认行为。为此,你可以添加prevent_default属性,用你想要阻止的handler的名称命名。这个属性可以用于多个handler,使用它们的名字通过空格分隔:

rsx! {
    a {
        href: "https://example.com",
        prevent_default: "onclick",
        onclick: |_| log::info!("link clicked"),
        "example.com"
    }
}

任何事件handler仍将被调用。

通常,在React或JavaScript中,你会在回调中的事件上调用"preventDefault"。Dioxus目前不支持这种行为。注意:这意味着你不能根据事件中的数据有条件地防止默认行为。

处理器属性

有时,你可能想要创建一个接受event handler的组件。一个简单的例子是一个FancyButton组件,它接受一个onclick处理器:

#[derive(PartialEq, Clone, Props)]
pub struct FancyButtonProps {
    onclick: EventHandler<MouseEvent>,
}

pub fn FancyButton(props: FancyButtonProps) -> Element {
    rsx! {
        button {
            class: "fancy-button",
            onclick: move |evt| props.onclick.call(evt),
            "click me pls."
        }
    }
}

然后,你可以像使用任何其他handler一样使用它:

rsx! {
    FancyButton {
        onclick: move |event| println!("Clicked! {event:?}"),
    }
}

注意:就像任何其他属性一样,你可以给处理器命名任何你想要的名字!你传递的任何闭包都将自动转换为EventHandler

异步事件处理器

作为属性传递的EventHandler不支持传递返回异步块的闭包。相反,你必须手动调用spawn来进行异步操作:

rsx! {
    FancyButton {
        // 这不行!
        // onclick: move |event| async move {
        //      println!("Clicked! {event:?}");
        // },

        // 这样可以!
        onclick: move |event| {
            spawn(async move {
                println!("Clicked! {event:?}");
            });
        },
    }
}

这只适用于作为属性的自定义event handler。

自定义数据

Event handler对任何类型都是通用的,所以你可以向它们传递任何你想要的数据,例如:

struct ComplexData(i32);

#[derive(PartialEq, Clone, Props)]
pub struct CustomFancyButtonProps {
    onclick: EventHandler<ComplexData>,
}

pub fn CustomFancyButton(props: CustomFancyButtonProps) -> Element {
    rsx! {
        button {
            class: "fancy-button",
            onclick: move |_| props.onclick.call(ComplexData(0)),
            "click me pls."
        }
    }
}

img