Rust前端框架Yew:写一个按钮组件

976 阅读2分钟

之前写的记事本应用,基本没有关注UI之类的,最近开始进一步学习Yew这个框架的一些东西。之前使用Vue的时候,那会使用Element UI这个组件库,简单的看了下源码,准备仿照着写一个按钮的组件,也算是对Yew的组件化的研究。

样式这块其实要比较重要,不然太丑了,直接使用Element UI的样式。

  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">

给我们的按钮起名为YewButton,相关参数主要参考Element UI按钮组件。yew_button.rs代码:

use yew::prelude::*;

pub enum Msg {}
pub struct YewButton {}

#[derive(Clone, PartialEq, Properties)]
pub struct YewButtonProps {
    #[prop_or_default]
    pub disabled: bool,
    #[prop_or_default]
    pub style: String,
    pub title: AttrValue,
    pub on_clicked: Callback<MouseEvent>,
    #[prop_or_default]
    pub loading:bool
}

impl Component for YewButton {
    type Message = Msg;
    type Properties = YewButtonProps;

    fn create(_ctx: &Context<Self>) -> Self {
        Self {}
    }

    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
        match msg {}
    }
    fn view(&self, ctx: &Context<Self>) -> Html {
        let title = ctx.props().title.clone();
        let disabled = ctx.props().disabled.clone();
        let style = ctx.props().style.clone();
        let loading = ctx.props().loading.clone();
        
        let onclick = ctx.props().on_clicked.reform(move |event: MouseEvent| {
            event.stop_propagation();
            event.clone()
        });

        let mut classes = Vec::new();
        classes.push(String::from("el-button"));

        if !style.is_empty() {
            let ss = format!("el-button--{}", style);
            classes.push(ss);
        }
        if disabled {
            classes.push(String::from("is-disabled"));
        }

        html! {
            <button class={classes!(classes.clone())} {onclick} disabled={disabled.clone()} >
            {title.clone()}
            if loading {
                <i class="el-icon-loading"></i>
            }
            </button>
        }
    }
}

下面是如何使用,components_test.rs代码

use gloo_console::log;
use yew::prelude::*;
use super::yew_button::YewButton;

pub enum Msg {
    BtnClick
}

pub struct ComponentsTest {
}

impl Component for ComponentsTest {
    type Message = Msg;
    type Properties = ();

    fn create(_ctx: &Context<Self>) -> Self {
        Self {
        }
    }

    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
        match msg {
            Msg::BtnClick=>{
                log!("按钮点击");
                false
            }
        }
    }
    fn view(&self, ctx: &Context<Self>) -> Html {
        let on_clicked = ctx.link().callback(move|_e:MouseEvent|{
            Msg::BtnClick
        });
        html! {
            <div class="center-container">
                <h1>{ "组件测试" }</h1>
                <YewButton style="primary" title="按钮测试" on_clicked={on_clicked.clone()} />
                <br/>
                <YewButton style="primary" title="按钮测试" loading={true}  on_clicked={on_clicked.clone()} />
            </div>
        }
    }
}

整个下来感觉还算顺利,写Rust得时刻面对编译不过的问题,感觉还是有不少的坑,相比JS,用Rust写前端目前来看还是有点卡。其实CSSHTML这些没有变,只是把JS换成了Rust, 浏览器相关的API也没有变,只是换一种写法了。对于Rust,因为运行环境变成了浏览器,所以有些东西也无法使用。虽然有不少语言可以编译成wasm,但是就目前来看Rust确实是最上心的一个。

为了学习Yew我单独创建了一个项目,以上完整的代码都在这个项目yew-lab里面。