# rtml
**Repository Path**: billgavin/rtml
## Basic Information
- **Project Name**: rtml
- **Description**: No description available
- **Primary Language**: Rust
- **License**: Apache-2.0
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2022-05-09
- **Last Updated**: 2022-05-09
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# rtml
在 Rust 中尝试描述 html/css
在通常情况下要在 Rust 中生成 html 除了手动拼字符串外最常用的方式是使用模板引擎, 但这回带来2个主要问题
1. 需要学习模板语法, 且不同模板引擎之间语法可能差异很大
2. 在模板中难以利用 Rust 类型系统, 以及在 IDE 中支持可能不佳
那有没有可能在 Rust 实现 html 那样可以比较方便地展示文档树形结构, 同时又能充分利用 Rust 的类型系统呢, rtml 正是这个想法的一次尝试.
## 使用
先看一个简单例子
```rust
use rtml::tags::*;
fn main() {
let page = html(
h1("hello world!")
);
println!("{}", page);
}
```
生成 html
```html
hello world!
```
可以看到在 rtml 中, html, h1 和 html 的 ``, `` 标签对应, 往 `html` 传入的参数是 ` ` 的 children, `html(h1(...))` 就如同往 `` 标签中间放入 `h1` 标签一样.
注意, 在 rtml 中, `h1`, `div`, 和 `title` 等都是普通的函数(以下简称**标签函数**), 没有使用任何过程宏, 对于有 LSP 支持的 IDE 来说, 悬浮显示, 智能补全, 跳转定义等都没有问题. 而且 rtml 对于标准 html 标签都提供了详细的文档, 方便使用.

### 灵活的 children 传入
对于 rtml 中任意一个标签函数, 其参数虽然只有一个, 但可传入其中, 作为 children 的类型非常多.
#### 常见的字面类型
```rust
// 布尔值
span(true)
// 浮点数
span(1.1f64)
// 字符串
span("hello")
// format! 也OK
let name = "Rookie";
span(format!("hello {name}"))
// 整数
span(666usize)
```
#### 更多类型
```rust
// 任意一个实现 Tag trait 的结构体
div(h1("hello"))
// 元组也OK
// div 传入的参数是一个 (H1, Hr, P) 元组
div((
h1("hello"),
hr(()),
p("this is some desc")
))
// Vec 也行
// ul 传入的是一个
ul(
[1, 2, 3]
.iter()
.map(|i| li(format!("item {i}")))
.collect::>()
)
// const generic array 也可以, 如传入 [Span; 2]
div([span(1), span(2)])
```
### 设置属性, 样式和绑定事件处理函数
在 html 标签上, 用户可以设置 id, class 样式等. 为了兼容 html 风格,样式设置格式, rtml 提供了 `style!`, 和 `prop!` 两个宏以方便属性设置. 而且 rtml 传入属性的方式也非常灵活.
如果查看 rtml 文档里某个标签函数参数结构体 xxArgs 的文档, 你会发现它实现很多 `From` 方法.

正是这些实现让 rtml 的构造函数很灵活.
对于 `` 等标签, 通常我们不关系他的 children, 而是要传入 charset 等属性, 这时候你可以这样传参.
```rust
meta(prop! {
charset = "utf-8"
})
```
对于某些标签来说, 属性, 样式和 children 都需要设置, 除了要求 children 必须在最后一个位置外, 属性和样式可以乱序
```rust
// 注意, 传入的一个三元素元组
div((
style!{color: "red"},
prop! { id = "app" },
p("hello")
))
```
下面是一个更复杂的例子
```rust
use rtml::prop;
use rtml::style;
use rtml::tags::*;
fn main() {
let page = html((
prop! { lang = "zh-cn" },
(
header((
meta(prop! { charset = "utf-8" }),
title("html file generated by Rust!"),
)),
body((
style! {
color: "olive";
text-align: "center"
},
(
h1("WOW"),
hr(()),
h2("循环"),
pre((
style! {},
code(
r#"[1, 2, 3].iter().map(|i| p(format!("paragraph {}", i))).collect::>()"#,
),
)),
div([1, 2, 3]
.iter()
.map(|i| p(format!("paragraph {}", i)))
.collect::>()),
hr(()),
h2("任意字面量"),
div((
style! { color: "black" },
(span(true), span(false), span(1u8), span(1.30f32)),
)),
hr(()),
footer(b("power by Rust!")),
),
)),
),
));
println!("{}", page);
}
```
生成的 html
```html
html file generated by Rust!
WOW
循环
[1, 2, 3].iter().map(|i| p(format!("paragraph {}", i))).collect::>()
paragraph 1
paragraph 2
paragraph 3
任意字面量
true
false
1
1.3
```
浏览器打开效果如下.

#### TODO 事件函数绑定