#web-frontend #front-end #web-apps #web #frontend-framework #framework

livid

livid是一个轻量级的Rust前端crate,用于通过WebAssembly创建Web应用。

19个版本

0.2.13 2022年7月24日
0.2.12 2022年5月26日
0.2.9 2022年4月28日
0.1.4 2022年4月7日

#285 in WebAssembly

每月49次下载

MIT许可证

87KB
2.5K SLoC

livid

livid是一个轻量级的Rust前端crate,用于通过WebAssembly创建Web应用。它提供了以下优势

  • 对web-sys的薄包装
  • 无vdom。
  • 无宏!
  • 后端无关。

要求

  • wasm32-unknown-unknown目标

rustuptarget add wasm32-unknown-unknown

用法

  • 安装livid-cli crate(简化Web应用的构建和打包)

cargo安装livid-cli

  • 您可以为CSS文件/URL添加链接,并使用Widget::set_class_name()来利用CSS样式。
  • 创建项目
[dependencies]
livid = "0.2"

在您的Rust源文件中

use livid::{enums::*, prelude::*, *};

enum Action {
    Increment(i32),
    Decrement(i32),
}

fn btn(action: Action) -> button::Button {
    let (label, color, step) = {
        match action {
            Action::Increment(v) => ("Increment", Color::Green, v),
            Action::Decrement(v) => ("Decrement", Color::Red, -v),
        }
    };
    let btn = button::Button::default().with_label(label);
    btn.set_label_size(20);
    btn.set_label_color(color);
    btn.set_margin(10);
    btn.set_padding(10);
    btn.set_frame(FrameType::RFlatBox);
    btn.add_callback(Event::Click, move |_| {
        let frame = widget::Widget::from_id("result").unwrap();
        let mut old: i32 = frame.text_content().unwrap().parse().unwrap();
        old += step;
        frame.set_text_content(Some(&old.to_string()));
    });
    btn
}

fn main() {
    let col = group::Column::default_fill();
    col.set_justify_content(AlignContent::Center);
    btn(Action::Increment(1));
    let f = frame::Frame::default().with_label("0").with_id("result");
    f.set_padding(20);
    f.set_label_size(20);
    btn(Action::Decrement(1));
    col.end();
}

image

  • 使用livid-cli构建和提供服务

livid buildlivid serve

  • 使用livid deploy构建具有wasm的前端桌面应用

livid deploy--宽度=600 --高度=400

低级API

Livid还有一个低级小部件API

use livid::{enums::*, prelude::*, *};

fn div() -> widget::Widget {
    widget::Widget::new(WidgetType::Div)
}

fn btn(i: i32) -> widget::Widget {
    let btn = widget::Widget::new(WidgetType::Button);
    let (label, col) = if i > 0 {
        ("Increment", "Green")
    } else {
        ("Decrement", "Red")
    };
    btn.set_text_content(Some(label));
    btn.set_style(Style::Color, col);
    btn.add_callback(Event::Click, move |_| {
        let result = widget::Widget::from_id("result").unwrap();
        let mut old: i32 = result.text_content().unwrap().parse().unwrap();
        old += i;
        result.set_text_content(Some(&old.to_string()));
    });
    btn
}

fn main() {
    document::Document::get().set_title("Counter");

    let btn_inc = btn(1);
    let btn_dec = btn(-1);

    let main_div = div();
    main_div.append(&btn_inc);
    main_div.append(&btn_dec);

    let result = div();
    result.set_id("result");
    result.set_text_content(Some("0"));
    result.set_style(Style::FontSize, "22px");

    let btns = document::Document::get().get_elements_by_tag_name("BUTTON");
    for btn in btns.iter() {
        // set their fontSize to 22 pixesl
        btn.set_style(Style::FontSize, "22px");
    }
}

带有CSS的低级示例

use livid::{
    document::Document,
    enums::WidgetType::{self, *},
    widget::Widget,
};

fn w(typ: WidgetType) -> Widget {
    Widget::new(typ)
}

fn main() {
    Document::get().set_title("Form");
    Document::add_css_link("https://cdn.jsdelivr.net.cn/npm/[email protected]/css/bulma.min.css");
    Document::add_css_link("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css");

    let form = w(Form);
    form.set_class_name("box");
    form.append(&{
        let div = w(Div);
        div.set_class_name("field");
        div.append(&{
            let label = w(Label);
            label.set_class_name("label");
            label.set_inner_html(r#"<span class='fa fa-envelope'></span> Email"#);
            label
        });
        div.append(&{
            let div = w(Div);
            div.set_class_name("control");
            div.append(&{
                let inp = w(Input);
                inp.set_class_name("input");
                inp.set_attribute("type", "email").unwrap();
                inp.set_attribute("placeholder", "[email protected]").unwrap();
                inp
            });
            div
        });
        div
    });
}

image

高级API

Livid不强制使用。您可以在其之上构建高级抽象

mod detail; // we define an OnEvent trait for our buttons
use crate::detail::{OnEvent, App, Settings};
use livid::{enums::*, prelude::*, *};

#[derive(Default, Copy, Clone)]
struct Counter {
    value: i32,
}

#[derive(Debug, Clone, Copy)]
enum Message {
    IncrementPressed,
    DecrementPressed,
}

impl App for Counter {
    type Message = Message;

    fn new() -> Self {
        Self::default()
    }

    fn title(&self) -> String {
        String::from("Counter - livid")
    }

    fn update(&mut self, message: Message) {
        match message {
            Message::IncrementPressed => {
                self.value += 1;
            }
            Message::DecrementPressed => {
                self.value -= 1;
            }
        }
    }

    fn view(&mut self) {
        let col = group::Column::default_fill();
        button::Button::default()
            .with_label("Increment")
            .on_trigger(Message::IncrementPressed);
        frame::Frame::default().with_label(&self.value.to_string());
        button::Button::default()
            .with_label("Decrement")
            .on_trigger(Message::DecrementPressed);
        col.end();
    }
}

fn main() {
    Counter::new().run(Settings {
        size: (300, 200),
        win_color: Some(Color::Rgb(Rgb(250, 250, 250))),
        ..Default::default()
    })
}

请参阅示例目录以获取更完整的示例。

依赖项

~6.5–8.5MB
~171K SLoC