Yew 实现路由

1,184 阅读2分钟

Yew

Yew 是一个使用 WebAssembly 创建多线程前端 web 应用程序的现代的 Rust 框架。

创建初始项目

使用 cargo 创建一个名为 router 的项目:

cargo new router
cd router

在 Cargo.toml 添加依赖:

[dependencies]
yew = "0.18"
yew-router = "0.15.0"

在 src/main.rs 添加以下初始代码:

use yew::{html, Component, ComponentLink, Html, ShouldRender};

pub enum Msg {
}

pub struct Router {
    link: ComponentLink<Self>,
}

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

    fn create(_props: Self::Properties, link: ComponentLink<Self>) -> Self {
        Self { link }
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        true
    }

    fn change(&mut self, _props: Self::Properties) -> ShouldRender {
        false
    }

    fn view(&self) -> Html {
        html!{
            "Hello,world!"
        }
    }
}

fn main() {
    yew::start_app::<Router>();
}

运行 trunk serve 并在打开网站会显示以下内容:

Hello,world!

在 mian.rs 引用以下内容:

use yew_router::prelude::*;
use yew_router::service::RouteService;
use yew_router::Switch;

然后添加路由结构:

#[derive(Switch, Clone)]
enum AppRoute {
    //匹配 url/bedroom 所有路径
    #[to = "/#/bedroom"]
    //匹配当前 url/ 的所有路径
    Bedroom(usize),
    #[to = "/"]
    Home,
}

Switch 的派生宏生成的实现将尝试按照从第一个到最后一个的顺序匹配每个变量,因此,如果任何路由都可能匹配两个指定的注释,那么第一个将匹配,第二个将永远不会尝试。

也就是说,如果 Home(/)在 Bedroom (/bedroom)之前,Bedroom 将不会被匹配到。

route 可能受到用户改变(来自浏览器)也可能受到程序的改变。可以接受或者发送路由更改消息进行更新。

首先,保存路由:

pub struct Router {
    link: ComponentLink<Self>,
    //用于设定路由
    route_service: RouteService<()>,
    //当前路由
    route: Route<()>,
    //路由代理
    router_agent: Box<dyn Bridge<RouteAgent>>,
}

设定路由更改消息:

pub enum Msg {
    ChangeRoute(Route<()>)
}

浏览器路由改变的回调中发送消息:

fn create(_props: Self::Properties, link: ComponentLink<Self>) -> Self {
    //处理路由
    let route_service = RouteService::new();
    Self { 
        link, 
        route_service:route_service,
        //当前路有
        route:route_service.get_route(),
        //当用户(浏览器)改变路由时发送消息
        router_agent:RouteAgent::bridge(link.callback(Msg::ChangeRoute))
     }
}

处理路由改变消息:

fn update(&mut self, msg: Self::Message) -> ShouldRender {
    match msg {
        Msg::ChangeRoute(route) => {
            self.route_service.replace_route(&route, ());
            self.route = route;
            ConsoleService::log("RouteChanged");
        }
    }
    true
}

运行 trunk serve 并改变路由,将在控制台看到 “RouteChanged”

http://127.0.0.1:8080/#/test

注意,如果改变 route 造成页面刷新将不会触发!

接着,匹配每个路由,确定网页具体内容:

fn view(&self) -> Html {
    html!{
        match AppRoute::switch(self.route.clone()) {
            Some(AppRoute::Bedroom)=> {"这里是卧室"},
            Some(AppRoute::Home)=> {"这里是家"},
            None=>{"理论来说到不了这……"}
        }
    }
}

运行,然后查看

http://127.0.0.1:8080 或者 http://127.0.0.1:8080/#/

http://127.0.0.1:8080/#/bedroom

也可以匹配消息:

#[derive(Switch, Clone)]
enum AppRoute {
    #[to = "/#/bedroom"]
    Bedroom,
    #[to = "/#/say:{}"]
    Say(String),
    #[to = "/"]
    Home,
}
/*
……
*/
fn view(&self) -> Html {
    let temp;
    html! {
        match AppRoute::switch(self.route.clone()) {
            Some(AppRoute::Bedroom)=> {"这里是卧室"},
            Some(AppRoute::Say(s))=>{
                temp = s;
                &temp
            },
            Some(AppRoute::Home)=> {"这里是家"},
            None=>{"理论来说到不了这……"}
        }
    }
}

测试

http://127.0.0.1:8080/#/say:Hello,world!