#dioxus #proc-macro #web-component

dioxus-web-component-macro

dioxus-web-component 处理宏

9 个不稳定版本 (3 个破坏性更新)

0.3.2 2024 年 6 月 2 日
0.3.1 2024 年 6 月 1 日
0.3.0 2024 年 5 月 31 日
0.2.2 2024 年 5 月 25 日
0.0.4 2024 年 5 月 12 日

#1056WebAssembly

Download history 358/week @ 2024-05-11 448/week @ 2024-05-18 317/week @ 2024-05-25 401/week @ 2024-06-01 30/week @ 2024-06-08 3/week @ 2024-06-15 37/week @ 2024-06-29 74/week @ 2024-07-27

每月 107 次下载
dioxus-web-component 中使用

MIT/Apache

49KB
1K SLoC

dioxus-web-component-macro

提供一个处理宏来构建 Dioxus 网络组件。

示例

该宏替换了 Dioxus 的 #[component] 宏。

use dioxus::prelude::*;
use dioxus_web_component::{web_component, DioxusWebComponent};
use wasm_bindgen::prelude::*;

#[web_component]
fn MyWebComponent(
  attr: Option<String>,
  event: EventHandler<i64>,
) -> Element {
  rsx ! {
    div {
      // ...
    }
  }
}

#[wasm_bindgen(main)]
pub fn main() {
  // Register the web component (aka custom element)
  register_my_web_component();
}
<!-- include the script generated with wasm-pack -->
<script type="module" src="my-web-component.js"></script>

<!-- in the body -->
<my-web-component attr="plop"></my-web-component>

使用方法

标签

自定义元素标签由组件名称构建。

默认情况下,标签是名称的短横线版本。例如,MyWebComponent 变为 my-web-component

您可以使用 tag 属性更改默认行为。

use dioxus::prelude::*;
use dioxus_web_component::{web_component, DioxusWebComponent};

#[web_component(tag = "plop-component")]
fn MyWebComponent(
  // ...
) -> Element { todo!() }
<!-- in the body -->
<plop-component></plop-component>

ℹ️ 信息:自定义元素标签名称有约束。宏会为您检查标签的有效性。请参阅 MDN - 有效的自定义元素名称

样式

您可以使用 style 属性提供网络组件样式。

use dioxus::prelude::*;
use dioxus_web_component::{web_component, InjectedStyle};

#[web_component(
  tag = "plop-greeting", 
  style = InjectedStyle::css(include_str!("./style.css"))
)]
fn Greeting(
  // ...
) -> Element {
  todo!()
}

dioxus_web_component::InjectedStyle 可以是包含在 HTML <style>...</style> 元素中的原始 CSS,或指向外部样式表的链接,或 InjectedStyle 样式的列表。

⚠️ 警告:网络组件被包装在一个带有 dioxus CSS 类的 HTML div 中。

组件参数

您的组件的每个参数都应该是一个属性、一个属性或一个事件。请注意,参数可以是属性和属性的组合。

处理宏试图通过查看其类型来检测参数的类型。如果类型以 EventHandler 开头,则它被期望是一个事件。但是,这种检测并不可靠,因此您可能需要添加一个注释来纠正此行为。

如果需要自定义行为,也需要这些注释。

属性

属性类似于 href HTML 元素。

您可以使用#[attribute]注解将参数强制转换为属性。

当属性值发生变化时,dioxus组件将被渲染。

属性的HTML值是一个String,因此您应该能够将该字符串解析为目标类型。

属性name

属性名默认是参数名的短横线命名法。您可以使用#[attribute(name = "my-custom-name")]选择另一个名称。

属性option

属性可以是可选的或不选的。宏尝试通过类型名称自动检测它。但是检测并不可靠,所以如果需要,您可以使用#[attribute(option = true)]来修复检测。

属性initial

属性需要有一个初始值。如果没有提供HTML属性或属性被删除时,将使用此值。

默认情况下,我们期望属性类型实现std::default::Default。如果不是这种情况,或者您想为属性使用其他值,您可以使用#[attribute(initial = String::from("World"))]提供您的默认表达式。

请注意,即使T没有实现自己的DefaultOption<T>也会使用DefaultNone值。

属性parse

HTML属性是字符串和可选的,因此我们需要将属性值转换为组件参数类型。

宏使用std::str::parse方法。这意味着目标类型需要实现std::str::FromStr特性。

在发生错误的情况下,使用初始值(见下文)。

如果您想更改此行为,可以提供您的解析表达式。

如果参数类型是可选的,此代码中使用解析表达式:let value = new_value.and_then(#parse);. 如果类型不是可选的,代码如下:let value = new_value.and_then(#parse).unwrap_or_else(|| #initial);.

解析表达式的预期类型是 FnOnce(String) -> Option<T>. 默认表达式是 |value| value.parse().ok().

例如,如果你有一个类型为 bool 的参数 required,并且你希望无论属性的任何内容,如果属性存在,值都为 true,你可以使用 #[attribute(parse = |s| !s.is_empty() )].

属性

在Rust代码的Rust端,属性像属性一样工作。属性不能通过纯HTML访问,你需要JavaScript来获取/设置属性。

除了 String 表示形式,你需要能够将Rust类型转换为JavaScript类型(这里是一个 wasm_bindgen::JsValue)。对于设置器,你需要进行相反的转换。

属性name

默认情况下,属性名是参数名的camelCase形式。你可以使用 #[property(name = "valueAsDate")] 选择另一个名称。

属性 readonly

如果设置为 true,它将避免从JavaScript端设置属性。默认情况下会生成获取器和设置器。

属性initial

属性需要有一个初始值。此值在组件初始化时使用。

默认情况下,我们期望属性类型实现 std::default::Default。如果不是这种情况,或者您想为您的属性使用另一个值,您可以使用以下代码提供默认表达式:#[property(initial = String::from("World"))].

属性 try_into_js

对于获取器,属性值应转换为 wasm_bindgen::JsValue。默认情况下,我们使用 std::convert::TryInto 实现方式。

注意,有多种方式来实现 TryInto<JsValue>,例如使用 impl TryFrom<T> for JsValue 或甚至 impl From<T> for JsValue。请参阅 Rust TryInto

您可以使用 try_into_js 属性提供您的自定义转换到 JsValue。解析表达式的预期类型是 FnOnce(T) -> Result<JsValue, _>。注意,我们并不关心错误类型,因为错误情况被忽略,并返回 undefined

默认表达式是 |value| value.try_into()

将自定义类型(包装了 bool)转换为示例

// ...
#[property(
    try_into_js = |prop| {
        let js_value = if prop.0 {
            JsValue::TRUE
        } else {
            JsValue::FALSE
        };
        Ok::<_, Infallible>(js_value)
    },
)]
prop2: MyProp,
// ...

#[derive(Clone, PartialEq, Default)]
struct MyProp(bool);

但在那种情况下,建议的方式是实现 From<MyProp> for JsValue

属性 try_from_js

对于设置器,属性值应从 wasm_bindgen::JsValue 转换。默认情况下,我们使用 std::convert::TryInto 实现方式。

请注意,实现TryInto<T>有许多方法,例如使用impl TryFrom<JsValue> for T或甚至impl From<JsValue> for T。参见Rust TryInto

您可以使用try_from_js属性提供您的自定义从JsValue的转换。解析表达式的期望类型是FnOnce(JsValue) -> Result<T, _>。请注意,我们不关心错误类型,因为错误情况被忽略。

默认表达式是 |value| value.try_into()

将自定义类型(包装了 bool)转换为示例

// ...
#[property(
    try_from_js= |value| Ok::<_, Infallible>(MyProp(value.is_truthy())),
)]
prop2: MyProp,
// ...

#[derive(Clone, PartialEq, Default)]
struct MyProp(bool);

但在那种情况下,推荐的方式是实现From<JsValue> for MyProp

事件

Web组件可以发送自定义事件。如果组件参数的类型是EventHandler,则参数被检测为事件。由于这种检测并不可靠,您可以使用#[event]注解强制参数为事件。

自定义事件细节对应于Dioxus EventHandler的泛型类型。

⚠️ 重要:事件类型需要实现Into<JsValue>并且是'static(不包含任何引用)。

您可能需要手动实现它。您可以使用serde-wasm-bindgengloo_utils::format::JsValueSerdeExtwasm_bindgen::UnwrapThrowExt来实现Into<JsValue>特质。

事件 name

HTML事件名称通过删除on_(或on)前缀并将名称转换为短横线命名法从参数名称检测得到。您可以通过name属性选择您的值,例如使用#[event]]来派发一个build事件。

事件 no_bubble

默认情况下,事件会冒泡到DOM中。您可以使用以下代码避免冒泡:#[event(no_bubble = true)]

事件 no_cancel

默认情况下,事件是可取消的。您可以使用以下代码避免冒泡:#[event(no_cancel = true)]

依赖关系

~0.6–1.1MB
~25K SLoC