Dioxus 的Router 项目(2)

159 阅读3分钟

构建一个Nest

在本章节中,我们将开始构建我们网站的 blog 部分,这将包括链接、嵌套路由和路由参数。

网站导航

我们的网站访问者不会知道我们网站上所有可用的页面和博客,因此我们应该为他们提供一个导航栏。我们的导航栏将是一系列链接,用于在我们页面之间跳转。

我们希望我们的导航栏组件在网站上的多个不同页面上渲染。与其复制代码,我们可以创建一个包装所有子路由的组件。这被称为布局组件。要告诉路由器在哪里渲染子路由,我们使用 Outlet 组件。

我们来创建一个新的 NavBar 组件:

#[component]
fn NavBar() -> Element {
    rsx! {
        nav {
            ul { li { "links" } }
        }
        // `Outlet` 组件将在 `Outlet` 组件内部渲染子路由(在这种情况下,只是 `Home` 组件)
        Outlet::<Route> {}
    }
}

接下来,让我们将我们的 NavBar 组件作为布局添加到我们的 Route 枚举中:

#[derive(Routable, Clone)]
#[rustfmt::skip]
enum Route {
    // 在 `NavBar` 布局下的所有路由将在 `NavBar` 的 `Outlet` 中渲染
    #[layout(NavBar)]
        #[route("/")]
        Home {},
    #[end_layout]
    #[route("/:..route")]
    PageNotFound { route: Vec<String> },
}

要在我们的 NavBar 中添加链接,我们总是可以使用 HTML 锚元素,但这有两个问题:

  1. 它会导致全页面刷新
  2. 我们可能会不小心链接到不存在的页面

相反,我们想使用 Dioxus 路由器提供的 Link 组件。

Link 与常规 <a> 标签类似。它接受一个目标和子元素。

与常规 <a> 标签不同,我们可以将我们的 Route 枚举作为目标传递。因为我们用 #[route(path)] 属性注解了我们的路由,Link 将知道如何生成正确的 URL。如果我们使用 Route 枚举,Rust 编译器将防止我们链接到不存在的页面。

我们来添加我们的链接:

#[component]
fn NavBar() -> Element {
    rsx! {
        nav {
            ul {
                li {
                    Link { to: Route::Home {}, "Home" }
                }
            }
        }
        Outlet::<Route> {}
    }
}

使用这种方法,Link 组件仅适用于我们应用程序内的链接。要了解更多关于导航目标的信息,请参见此处。

现在你应该在页面顶部看到一个链接列表。点击其中一个,你应该可以无缝地在页面之间跳转。

URL 参数和嵌套路由

许多网站,如 GitHub,将参数放在他们的 URL 中。例如,https://github.com/DioxusLabs 利用域名后的文本动态搜索并显示有关组织的相关内容。

我们希望将我们的博客存储在数据库中,并按需加载。我们也希望我们的用户能够发送链接给特定的博客文章。与其在编译时列出所有博客标题,我们可以制作一个动态路由。

我们的 blog 路径将看起来像 /blog/myBlogPagemyBlogPage 是 URL 参数。

首先,我们来创建一个布局组件(类似于导航栏),它包装 blog 内容。这允许我们添加一个标题,告诉用户他们正在阅读博客。

#[component]
fn Blog() -> Element {
    rsx! {
        h1 { "Blog" }
        Outlet::<Route> {}
    }
}

现在我们将创建另一个索引组件,当没有选择博客文章时将显示:

#[component]
fn BlogList() -> Element {
    rsx! {
        h2 { "Choose a post" }
        ul {
            li {
                Link {
                    to: Route::BlogPost {
                        name: "Blog post 1".into(),
                    },
                    "Read the first blog post"
                }
            }
            li {
                Link {
                    to: Route::BlogPost {
                        name: "Blog post 2".into(),
                    },
                    "Read the second blog post"
                }
            }
        }
    }
}

我们还需要创建一个显示实际博客文章的组件。这个组件将接受 URL 参数作为属性:

// name 属性来自 /:name 路由段
#[component]
fn BlogPost(name: String) -> Element {
    rsx! { h2 { "Blog Post: {name}" } }
}

最后,让我们告诉路由器这些组件:

#[derive(Routable, Clone)]
#[rustfmt::skip]
enum Route {
    #[layout(NavBar)]
        #[route("/")]
        Home {},
        #[nest("/blog")]
            #[layout(Blog)]
            #[route("/")]
            BlogList {},
            #[route("/post/:name")]
            BlogPost { name: String },
            #[end_layout]
        #[end_nest]
    #[end_layout]
    #[route("/:..route")]
    PageNotFound {
        route: Vec<String>,
    },
}

就是这样!如果你访问 /blog/1,你应该能看到我们的示例文章。

结论

在本章节中,我们利用了 Dioxus 路由器的 Link 和路由参数功能来构建了我们应用程序的 blog 部分。在下一章中,我们将讨论导航目标(比如我们传递给链接的那个)的工作原理。

img