3个不稳定版本
0.1.2 | 2019年11月3日 |
---|---|
0.1.1 | 2019年11月3日 |
0.0.3 | 2019年10月31日 |
#23 in #constructing
14KB
350 行
🏗️ View
[dependencies]
view = "0.4"
Rust中构建视图层次结构有些繁琐。这是一个以非框架特定方式构建视图的宏。与JSX等技术相比,它更注重结构,并借鉴了一些SwiftUI的思想。
此示例展示了所有可能的操作
let images = vec!["coffee.png","cream.png","sugar.png"];
let show_coupon = false;
let coupon = getTodaysCoupon();
let v = view!{
VStack {
Image("company.png")
Button(text:"order".to_string(),style:BOLD)
.on_click(|| do_order()) {
Image("order_icon.png")
}
For(i in images.iter()) { Image(i) }
If(show_coupon) { coupon }
Legal
}
};
以下是此宏可以为您节省的所有代码。
let images = vec!["coffee.png", "cream.png", "sugar.png"];
let show_legal = false;
let s = {
let mut o = VStack {
..Default::default()
};
o.add_view_child({
let mut o = Image::new("company.png");
o
});
o.add_view_child({
let mut o = Button {
text: "order".to_string(),
style: BOLD,
..Default::default()
};
o.on_click(|| do_order());
o.on_click(|| do_order());
o.add_view_child({
let mut o = Image::new("order_icon.png");
o
});
o
});
for i in images.iter() {
o.add_view_child({
let mut o = Image::new(i);
o
});
}
o.add_view_child({
let mut o = Footer {
..Default::default()
};
o
});
if show_legal {
o.add_view_child({
let mut o = Legal {
..Default::default()
};
o
});
}
o
};
此项目不是针对特定框架的,但它有一些规则
- 有子视图的视图必须实现
add_view_child
函数 - 视图必须实现Default特质以构建属性(例如
Button(text:"click me")
) - 视图必须有一个 'new' 构造函数以进行简单构建(例如
Button("click me")
)
以下是一个实现这些规则的基本示例,尽管您可以选择任何方式,使用任何特质来实现。
trait View {}
#[derive(Default)]
struct VStack {
direction: u8,
children: Vec<Box<View>>
}
impl VStack {
fn new(direction:u8) -> Self {
VStack{ direction:direction, children:vec![] }
}
fn add_view_child<'a, T>(&'a mut self, child: Box<T>)
where
T: 'static + View,
{
self.children.push(child);
}
}
impl View for VStack {}
#[derive(Default)]
struct Button {
text:String
}
impl Button {
fn new(text:String) -> Self {
Button{text:text}
}
}
impl View for Button {}
让我们创建一个虚拟DOM
use view::*;
struct VNode {
vnode_type: &'static str,
children: Vec<VNode>,
classes: Vec<String>,
text: Option<String>,
}
impl VNode {
fn add_class(&mut self, c: &str) {
self.classes.push(c.to_string())
}
fn add_view_child(&mut self, child: VNode) {
self.children.push(child);
}
fn render_to_string(&self) -> String {
if let Some(t) = &self.text {
t.clone()
} else {
format!(
"<{} class=\"{}\">{}</{}>",
self.vnode_type,
self.classes.join(","),
self.children
.iter()
.map(|c| c.render_to_string())
.collect::<Vec<String>>()
.join(""),
self.vnode_type
)
}
}
}
type Div = VNode;
impl Default for Div {
fn default() -> Self {
VNode {
vnode_type: "div",
children: vec![],
classes: vec![],
text: None,
}
}
}
type Text = VNode;
impl Text {
fn new(t: &str) -> Self {
VNode {
vnode_type: "text",
children: vec![],
classes: vec![],
text: Some(t.to_string()),
}
}
}
fn main() {
let html = view! {
Div.add_class("greeting"){
Text("Hello World!")
}
};
println!("{}", html.render_to_string());
}
许可证
此项目许可协议为以下之一
- Apache许可证2.0版(LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT许可证(LICENSE-MIT 或 https://open-source.org.cn/licenses/MIT)
由您选择。
贡献
除非您明确说明,否则您提交给view的任何有意包含的贡献,根据Apache-2.0许可证定义,应按照上述方式双重许可,不附加任何其他条款或条件。
依赖项
~5KB