5个版本
0.3.0 | 2020年10月28日 |
---|---|
0.1.3 | 2020年5月30日 |
0.1.2 | 2020年5月30日 |
0.1.1 | 2020年5月30日 |
0.1.0 | 2020年5月30日 |
432 在 WebAssembly 中
每月 22 次下载
29KB
771 行
Afterglow
Afterglow是一个基于 dodrio 和 typed-html 的实验性Rust前端框架
特性
-
虚拟DOM
使用dodrio提供的vdom来处理重渲染。
-
类似JSX的语法
使用typed-html提供的类似JSX的宏来创建视图。
-
受Elm启发的容器
每个数据容器都有自己的生命周期,只有在选择的情况下才会触发重渲染。
-
使用特对象来鼓励在UI探索上的自由度
虽然拥有严格的数据模型并提供与严格视图/突变集紧密结合的视图是维护组件整洁概览的好方法,但很多时候构建前端将需要更灵活的工作流程。这意味着对于相同的数据模型,项目中的不同用例可能有多个,并且每个用例都需要一组专有的数据突变。在Renderer和Messenger上使用特对象允许容器对渲染和突变的时间和方式有更少的约束。
-
依赖于消息总线在异构容器之间共享事件
通过将容器的消息发送者注册到一个集中式总线,容器可以为其设计对总线事件的响应。因此可以实现父子、兄弟通信。
示例
假设你想要将相同的数据作为视觉元素重用,
use crate::prelude::*;
#[derive(Default)]
pub struct Model {
status: bool,
clicked: i32,
}
impl LifeCycle for Model {
fn new(render_tx: Sender<()>) -> Self {
Model::default()
}
}
同时保持一个处理数据突变和业务逻辑的单个容器,我们可以创建多组具有自身UI逻辑封装的视图。
struct TableView;
impl Renderer for TableView {
type Target = Model;
type Data = Model;
fn view<'a>(
&self,
target: &Self::Target,
ctx: &mut RenderContext<'a>,
sender: MessageSender<Self::Data>,
) -> Node<'a> {
let bump = ctx.bump;
dodrio!(bump,
<table class="table">
<thead>
<tr>
<th>"counts"</th>
<th>"status"</th>
</tr>
</thead>
<tbody>
<tr>
<td>{ text(bf!(in bump, "clicked: {} times", target.clicked).into_bump_str())}</td>
<td>{ text(bf!(in bump, "status: {}", target.status).into_bump_str())}</td>
</tr>
</tbody>
</table>
)
}
}
struct ButtonView;
impl Renderer for ButtonView {
type Target = Model;
type Data = Model;
fn view<'a>(
&self,
target: &Self::Target,
ctx: &mut RenderContext<'a>,
sender: MessageSender<Self::Data>,
) -> Node<'a> {
let bump = ctx.bump;
dodrio!(bump,
<div
onclick={ consume(|e: web_sys::Event| { ClickMsg::Clicked }, &sender)}
class="button">"clicked to increase stats"</div>
)
}
}
并且不需要定义一个巨大的枚举让容器处理所有传入的事件,我们可以有一组仅包含相关变体的Messenger集合。以后可以定义新的,而不必更改模型的实现。
pub enum ClickMsg {
Clicked,
}
impl Messenger for ClickMsg {
type Target = Model;
fn update(
&self,
target: &mut Self::Target,
sender: MessageSender<Self::Target>,
render_tx: Sender<()>,
) -> bool {
match self {
ClickMsg::Clicked => {
target.clicked += 1;
target.status = !target.status;
true
}
}
}
}
通过视图提供者,即Renderer,与数据模型解耦,我们可以更自由地组合页面。用户可以将其UI逻辑分离到其自己的视觉元素中。
#[derive(Default)]
struct MainView;
impl Renderer for MainView {
type Target = Model;
type Data = Model;
fn view<'a>(
&self,
target: &Self::Target,
ctx: &mut RenderContext<'a>,
sender: MessageSender<Self::Data>,
) -> Node<'a> {
let bump = ctx.bump;
dodrio!(bump,
<div>
<div class="hero is-light">
<div class="hero-body">
<div class="container">
<div class="card">
<div class="card-content">
{ TableView.view(target, ctx, sender.clone())}
</div>
<div class="card-footer">
<div class="card-footer-item">
{ ButtonView.view(target, ctx, sender)}
</div>
</div>
</div>
</div>
</div>
</div>
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.css"/>
</div>
)
}
}
因此,根据定义,一个应用程序是一个给定的数据模型,它有一个默认的Renderer。
pub fn init_example() {
Entry::init_app::<Model, MainView>("app");
}
依赖项
~12–24MB
~360K SLoC