2 个不稳定版本
0.2.0 | 2021年6月28日 |
---|---|
0.1.0 | 2021年6月16日 |
#1887 在 网页编程
每月 21 次下载
105KB
2.5K SLoC
Pinwheel
Pinwheel 是一个用于使用 Rust 编写网页用户界面的库。
示例
下面的示例在每次按下 <p>
时增加一个 <button>
的值。
let body = dom::window().unwrap().document().unwrap().body().unwrap().into();
let count = Mutable::new(0);
let on_click = {
let count = count.clone();
move |_| {
count.replace_with(|count| *count + 1);
}
};
let count_text = count.signal().map(|count| p().child(count.to_string()));
let increment_button = button().onclick(on_click).child("Increment");
let counter = div()
.style(style::DISPLAY, "grid")
.style(style::JUSTIFY_CONTENT, "start")
.child_signal(count_text)
.child(increment_button);
App::new(body, counter).forget();
特性
精细粒度反应性
Pinwheel 使用 futures-signals 包来更新随着应用状态变化而确切需要更新的 DOM 节点。无需虚拟 DOM!
同构渲染
当编译成浏览器版本时,Pinwheel 通过创建 DOM 节点进行渲染。在服务器上,它通过将 HTML 写入字符串进行渲染。
let root = p().child("Hello, World!");
// On the server...
assert_eq!(root.to_string(), "<p>Hello, World!</p>");
// On the client...
App::new(dom_node, root).forget();
部分激活
在服务器渲染后,在客户端使应用的一部分交互式。在下面的示例中,dynamic_component
将在服务器和客户端渲染,但 static_component
只会在服务器上渲染。
let root = p().child("Hello, World!");
// On the server...
let html = div()
.child(static_component)
.child(Dehydrate::new("hydration_id", dynamic_component))
.to_string();
// On the client...
hydrate("hydration_id");
无宏构建器
Pinwheel 提供了无宏的 DOM 元素静态类型构建器,因此您将获得 rustfmt
格式化和 rust-analyzer
自动完成的全部好处。
let count_p = count.signal().map(|count| p().child(count.to_string()));
let increment_button = button().onclick(on_click).child("Increment");
let root = div()
.style(style::DISPLAY, "grid")
.style(style::JUSTIFY_CONTENT, "start")
.child_signal(count_p)
.child(increment_button);
组件
将应用组织成自包含的组件。
use pinwheel::prelude::*;
struct Alert {
title: String,
color: Option<String>,
children: Vec<Node>,
}
impl Component for Alert {
fn into_node(self) -> Node {
div()
.style(style::BACKGROUND_COLOR, self.color)
.child(h1().child(self.title))
.children(self.children)
.into_node()
}
}
组件构建器
组件通常有几个必需字段和许多可选字段。Pinwheel 提供了一个 derive 宏,使使用这些组件变得简单。
#[derive(ComponentBuilder)]
struct Alert {
// required field
title: String,
// optional field
#[optional]
color: Option<String>,
#[children]
children: Vec<Node>,
}
现在,您可以使用构建器模式创建一个警报。
Alert::new("Alert!")
.color("green".to_owned())
.child("An alert occurred!")
依赖项
~12MB
~240K SLoC