3 个不稳定版本
0.2.1 | 2020年6月2日 |
---|---|
0.2.0 | 2020年6月1日 |
0.1.2 | 2019年12月20日 |
#14 in #full-stack
25 每月下载量
在 2 crate 中使用
130KB
3.5K SLoC
Reign View 是一个基于组件的 HTML 模板库,受 Vue.js 模板启发。
此库使得使用模板变得如同甜点般简单。它使用基于 HTML 的模板语法,这些语法是有效的,并且可以被符合规范的浏览器和 HTML 解析器解析 [1][2]。它主要考虑了易用性,其次是未来的扩展性、模块化和定制。
此库还提供了多个辅助工具和功能门,用户可以使用它们进行定制,使库可以直接与或没有 reign_router 一起使用。
有关更多详细信息,请参阅 API 文档。
注意:最低支持的 Rust 版本是 1.45.0
目录
快速入门
-
将 reign 添加到您的代码库中,省略默认功能并启用
view
功能[dependencies] reign = { version = "*", features = ["view"], default-features = false }
-
在您的
main.rs
中初始化模板use reign::prelude::*; // If your templates live under `src/views` folder views!("src", "views");
-
在
src/views/pages/about.html
中编写一个模板<p> {{ name }} <sub>aged {{ age: u8 }}</sub> </p>
-
渲染模板
use reign::prelude::*; let (name, age) = ("John", 28); // The macro automatically captures all the // variables it needs, builds the view to display // and returns a `String` // // `pages::about` is the unique path of the above template render!(pages::about)
工作原理
这个模板库中有多个步骤。
- 从 HTML 模板构建一个 视图。
- 将 视图 渲染成一个 String。
构建
假设您已经在前面的部分编写了相应的路径下的模板。
现在,当您通过编写以下内容来初始化模板库时
use reign::prelude::*;
views!("src", "views");
库将展开 views!
宏,变成以下类似的形式
// It will create a module which is always called `views`
mod views {
// Then it will create a module for `pages` subdirectory
pub mod pages {
// Then it will create a struct for the template file
pub struct About<'a> {
// It will add a raw string field for every variable
// found which does not have a type described
pub name: &'a str,
// It will add a typed field for every variable found
// that was given a type (once in a template is enough)
pub age: u8,
}
use std::fmt::{Display, Formatter, Result};
// Then it will implement std::fmt::Display for it
impl Display for About<'_> {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "{}{}{}{}{}",
"<p>\n ", self.name, "\n <sub>aged ", self.age, "</sub>\n</p>"
)
}
}
}
}
上面的展开是近似的。它们在展开的方式或其他内部使用的事物上可能有些小变化。
您可以在下面了解更多关于模板语法的详细信息 这里
渲染
当启用纯视图功能时,当您尝试渲染如下模板时
use reign::prelude::*;
let (name, age) = ("John", 28);
render!(pages::about);
这个库扩展了 render!
宏,使其变成以下的样子
format!("{}", crate::views::pages::About {
name: name.as_ref(),
age,
});
它返回以下字符串
<p>
John
<sub>aged 28</sub>
<p>
模板语法
在我们开始讨论模板语法之前,让我们就本节的一些术语达成一致,以便稍后更容易引用。
表达式 是 Rust 语言中所有表达式类型的一个自定义子集。你可以在这里了解更多。
模式 是一个自定义的 Rust 模式语法,其中允许的表达式仅限于上面段落中定义的。你可以在这里了解更多。
字段 指的是在初始化模板库时,由 views!
宏构建的用于模板的 struct 的字段。
模板中使用的所有 HTML 样式标签都应该通过自闭合语法或结束标签来关闭。唯一的例外是那些根据 HTML 规范默认可以自闭合的标签,称为 空元素。
文本
模板化的最基本形式是使用 "mustache" 语法(双大括号)进行的 "插值"。
<span>Message: {{ msg }}</span>
mustache 标签将被替换为 msg
字段 的值。你还可以在 mustache 标签内使用 表达式。任何实现了 std::fmt::Display
的类型都可以作为 mustache 标签定义的 表达式 的最终结果。
<span>Word Count: {{ msg.len() }}</span>
属性
插值也可以用于属性值。
<div title="Application - {{ page_name }}"></div>
如果你想在属性值中嵌入 "
以内的 表达式,你可以遵循 HTML 规范,并用 '
将值包围。
<div title='Application - {{ "Welcome" }}'></div>
变量属性
如果你想有一个完全由一个 mustache 标签插值,不包含其他内容的属性,你可以这样做。
<div :title="page_name"></div>
属性 title
的值将是 page_name
字段的值。
控制属性
该库不允许在 mustache 标签内作为表达式使用 if
条件和 for
循环。你可以在 HTML 标签上使用控制属性来完成这个任务。
<div !if='page_name == "home"'>Welcome</div>
<div !else>{{ page_name }}</div>
上面的模板根据提供给 !if
控制属性的 表达式 打印第一个或第二个 div
。
正如预期的那样,也支持 !else-if
。
for
循环也使用与下面类似的控制属性语法。
<div !for="char in page_name.chars()">{{ char }}</div>
上面的模板为 page_name
字段中的所有字符打印 div
标签。除了控制属性中的名称不同外,!for
需要 模式 in 表达式 语法。
分组元素
由于 !if
和 !for
是属性,它们需要附加到单个标签上。但有时,你可能需要渲染多个元素。在这种情况下,你可以使用 template
标签,它像一个不可见的包装器。
<template v-if="condition">
<h1>{{ title }}</h1>
<p>{{ content }}</p>
</template>
模板不允许在根处定义多个元素。这意味着,你可以使用 template
标签来在模板的根处分组元素。
<template>
<!DOCTYPE html>
<html></html>
</template>
类 & 样式绑定
待实现
组件
每个模板默认都可以用作组件,因此是可重用的。让我们假设我们有一个模板 src/views/shared/button.html
,如下所示
<button :href="href">{{text}}</button>
为此生成的视图如下所示
struct Button<'a> {
href: &'a str,
text: &'a str,
}
上述模板可以使用以下语法在其他模板中使用
<navbar>
<shared:button href="/" text="Dashboard" />
<shared:button href="/settings" text="Account" />
</navbar>
组件上的属性与上面描述的正常HTML元素上的属性工作方式相同。
任何模板都可以用作组件。我们可以通过使用它的标签引用来引用模板。标签引用可以通过将组件路径中的所有部分转换为大写并使用冒号(:
)连接来实现。位于 src/views/users/avatar.html
的模板可以使用 users:avatar
,同样,位于 src/views/common/simple/small_icon.html
的模板可以使用 common:simple:small-icon
插槽
与HTML元素一样,将内容传递到组件中通常很有用,例如
<div>
<shared:button href="/">
<span class="icon"></span>
Dashboard
</shared:button>
</div>
幸运的是,我们可以通过在 button.html
中使用我们自定义的 slot
元素来实现这一点。
<button :href="href">
<slot></slot>
</button>
上面的 <slot></slot>
会在使用时被替换为 shared:button
元素内部描述的元素。
作用域
当我们在一个组件的插槽中使用变量时,例如
<div>
<shared:button href="/">{{ link_text }}</shared:button>
</div>
该插槽尝试访问此模板的字段(即相同的 scope
)。插槽无法访问 <shared:button>
的字段。例如,尝试访问 href
将不会成功
<div>
<shared:button href="/">{{ href }}</shared:button>
</div>
它将在模板本身上创建一个 href
字段。
回退
待实现
命名插槽
有时拥有多个插槽很有用。例如,在一个具有以下模板的 <base-layout>
组件中
<div class="container">
<header>
<!-- We want header content here -->
</header>
<main>
<!-- We want main content here -->
</main>
<footer>
<!-- We want footer content here -->
</footer>
</div>
对于这些情况,<slot>
元素有一个特殊的属性 name
,可以用来定义额外的插槽
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
没有 name
的 <slot>
通道隐式具有名称 "default"
。
要为命名插槽提供内容,我们可以在 <template>
上使用特殊属性,提供插槽的名称
<layout:base>
<template #header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template #footer>
<p>Here's some contact info</p>
</template>
</layout:base>
现在,<template>
元素内部的全部内容都将传递给相应的插槽。任何未包裹在 <template>
中的内容都假定为默认插槽的内容。
然而,如果您希望明确,仍然可以将默认插槽内容包装在 <template>
中。
辅助工具 & 功能门
在 Reign 上有多个功能门,帮助用户选择他们想要的库功能。
请参阅 示例 了解如何使用它们。
有关宏的使用信息,请参阅 reign_derive。
视图
views!
可以用来构建视图。render!
可以用来将视图渲染为字符串。
视图后端
views!
可以用来构建视图。- 启用
render
辅助函数和render!
将视图渲染为响应,供 reign_router 后端处理器使用。 - 启用
redirect
辅助函数,用于 reign_router 后端处理器。 - 启用
json
辅助函数和json!
为 reign_router 后端处理器构建响应。
附录
表达式
下面描述了允许的表达式,其中 bop
是二元运算符,而 uop
是一元运算符。...
表示可能的重复。
字面量
标识符
[表达式, ...]
表达式 bop 表达式
uop 表达式
表达式(表达式, ...)
表达式.标识符
表达式.数字
表达式[表达式]
(表达式)
[表达式;表达式]
(表达式, ...)
&表达式
表达式as 类型
表达式: 类型
表达式..表达式
类型 {标识符:表达式, ..表达式, ... }
模式
下面描述了允许的模式,其中 expr
代表上述提到的 表达式。...
表示可能的重复。
标识符
_
&模式
类型 {模式, .., ... }
(模式, ...)
类型(模式, .., ...)
注解
- 标签名称可以包含
:
,这并不完全符合纯 HTML5 规范,但大多数解析器都支持它。 - 我们还假设解析器是根据 Web Components 规范制作的。
依赖关系
~3.5–6.5MB
~121K SLoC