- 支持试读
开启 dioxus 之旅
本章将讨论 dioxus 的安装、项目创建、运行和构建。 - 支持试读
dioxus 组件与 rsx
本章将开始第一个案例:计数器的编写。首先,我们需要学习 dioxus 组件的编写和 rsx 语法。 - 支持试读
计数器
本章我们将开始编写计数器。你将学习到:事件处理、状态管理、组件通讯、集成 Tailwind CSS 等知识。 - 支持试读
博客
本章我们将实现博客,你将学习到:dioxus 路由、获取远程数据、条件渲染、列表渲染等知识。 全局状态
本章我们开始最后一个案例:阅后即焚的开发。在真正进行开发之前,我们还需要掌握一些基础知识,本章我们将学习 dioxus 的全局状态。布局与嵌套路由
本章我们将讨论 dioxus 的布局与嵌套路由。表单处理
本章我们将学习 dioxus 的表单处理。和 React 类似,dioxus 也分为受控表单和非受控表单。阅后即焚前台UI
本章我们开始编写阅后即焚的前台UI。- 支持试读
阅后即焚API
本章我们使用 AXUM 开发阅后即焚的前台 API。 整合阅后即焚前端和API
本章将对阅后即焚前端和API进行整合。- 支持试读
编译和部署
本章我们将讨论 dioxus web 的编译和部署到 NGINX。 【加餐】dioxus 服务端渲染
本章使用前文的『博客』中的用户数据为案例,来讲解 dioxus 服务端渲染。
dioxus 组件与 rsx
- 7
- 2025-04-30 21:17:27
本章将开始第一个案例:计数器的编写。首先,我们需要学习 dioxus 组件的编写和 rsx 语法。
Dioxus 和 React
如果你用过 React,你会发现 Dioxus 和它非常相似,你甚至可以将其视为 rust 版的 React。
- 和 React 一样,Dioxus 也是通过组件来组织项目的。
- React 使用 jsx 来编写组件,dioxus 使用 rsx 来编写组件。
如果你愿意,建议花点时间学习一下 React
创建项目
开始之前,我们需要创建一个名为 calc
的 dioxus 项目:
dx new calc
我们来看一下文件结构:
├── assets
│ ├── favicon.ico
│ ├── header.svg
│ └── main.css
├── Cargo.toml
├── Dioxus.toml
├── README.md
└── src
└── main.rs
assets
:放置图片、CSS等静态资源Cargo.toml
:如果连这都不知道,就不要搞了Dioxus.toml
:Dioxus 配置文件src
:源代码
初印象
打开 src/main.rs
,我们先来看看 dx
生成的 dioxus Web 项目的代码:
use dioxus::prelude::*;
const FAVICON: Asset = asset!("/assets/favicon.ico");
const MAIN_CSS: Asset = asset!("/assets/main.css");
const HEADER_SVG: Asset = asset!("/assets/header.svg");
fn main() {
dioxus::launch(App);
}
- 通过
dioxus::launch()
函数来启动 dioxus 应用 - 其中的参数
App
是一个组件定义
我们看看 App
组件:
#[component]
fn App() -> Element {
rsx! {
document::Link { rel: "icon", href: FAVICON }
document::Link { rel: "stylesheet", href: MAIN_CSS }
Hero {}
}
}
如果没有函数体中的 rsx!
宏,那么,这个函数非常简单,不是吗?
#[component]
指令宏,你可以把它看成将某个函数标记为组件──实际上,远非如此,后文会进行讨论。fn App() -> Element
:定义一个App
函数,返回值是Element
- 这个函数明显不符合 Rust 的命名规范
- 在 rust 中,函数的命名规范是蛇形命名
- 但在 dioxus 中,组件名是大驼峰命名。
#[component]
帮我们做了设置,让 rust 编译器不会对组件的命名发出警告
- 这个函数明显不符合 Rust 的命名规范
rsx!
宏:可以书写 rsx 语法document::Link { rel: "icon", href: FAVICON }
:用于添加浏览器的收藏图标document::Link { rel: "stylesheet", href: MAIN_CSS }
:用于引入 CSS 样式Hero{}
:调用了Hero
组件
#[component]
pub fn Hero() -> Element {
rsx! {
div {
id: "hero",
img { src: HEADER_SVG, id: "header" }
div { id: "links",
a { href: "https://dioxuslabs.com/learn/0.6/", "📚 Learn Dioxus" }
a { href: "https://dioxuslabs.com/awesome", "🚀 Awesome Dioxus" }
a { href: "https://github.com/dioxus-community/", "📡 Community Libraries" }
a { href: "https://github.com/DioxusLabs/sdk", " Dioxus Development Kit" }
a { href: "https://marketplace.visualstudio.com/items?itemName=DioxusLabs.dioxus", "💫 VSCode Extension" }
a { href: "https://discord.gg/XgGxMSkvUM", "👋 Community Discord" }
}
}
}
}
其中的 rsx 看似很复杂对吗?其实,它对应的 HTML 如下:
<div id="hero">
<img src="{HEADER_SVG}" id="header" />
<div id="links">
<a href="https://dioxuslabs.com/learn/0.6/">📚 Learn Dioxus</a>
<a href="https://dioxuslabs.com/awesome">🚀 Awesome Dioxus</a>
...
<a href="https://discord.gg/XgGxMSkvUM">👋 Community Discord</a>
</div>
</div>
清理初始代码
我们先来清理一下初始文件和代码。
- 首先,删除
assets/headers.svg
文件 - 然后,打开
src/main.rs
:- 删除
HEADER_SVG
常量,即删除const HEADER_SVG: Asset = asset!("/assets/header.svg");
- 删除
Hero
组件的定义,以及App
组件中对该组件的调用
- 删除
最终,src/main.rs
代码如下:
use dioxus::prelude::*;
const FAVICON: Asset = asset!("/assets/favicon.ico");
const MAIN_CSS: Asset = asset!("/assets/main.css");
fn main() {
dioxus::launch(App);
}
#[component]
fn App() -> Element {
rsx! {
document::Link { rel: "icon", href: FAVICON }
document::Link { rel: "stylesheet", href: MAIN_CSS }
div { "Hello, 世界" }
}
}
定义组件
我们大概看了 dioxus 如何定义组件。现在,我们手动定义一个简单的组件。
fn Hello() -> Element {
rsx! {
div { "Hello, 世界" }
}
}
在 App
组件中调用:
#[component]
fn App() -> Element {
rsx! {
document::Link { rel: "icon", href: FAVICON }
document::Link { rel: "stylesheet", href: MAIN_CSS }
Hello {}
}
}
fn Hello() -> Element {
let name = "AXUM中文网";
rsx! {
div { "Hello, {name}" }
}
}
rsx 允许使用 {}
进行插值操作,如上例的 div { "Hello, {name}" }
。
现在,我们为Hello
组件添加 Props
#[derive(Props, Clone, PartialEq)]
struct HelloProps {
name: String,
}
fn Hello(props: HelloProps) -> Element {
rsx! {
div { "Hello, {props.name}" }
}
}
HelloProps
结构体就是Hello
组件的 Props,它包含一个name
成员- 它需要
#[derive(Props, Clone, PartialEq)]
- 它需要
fn Hello(props: HelloProps)
,Hello
组件接收HelloProps
类型的参数
对于组件而言,Props是一个非常重要且常用的。如果每个组件的Props都要这样单独定义一个结构体,那会非常麻烦。好在 dioxus 提供了 #[component]
,以下代码和上述代码效果一样:
#[component]
fn Hello(name: String) -> Element {
rsx! {
div { "Hello, {name}" }
}
}
#[component]
宏:
- 自动将组件的 Props (参数)定义对应的结构体
- 会消除函数命名不规范的警告
rsx
dioxus 使用的是一种称为 rsx
的语法来生成虚拟DOM。我们来看一下最简单的 rsx:
它将生成对应的虚拟DOM:
<div>
Hello, 世界
</div>
由此可知:在 rsx 中,某个元素中的字符串,就是它渲染到页面的文本内容。
rsx! {
div {
id:"msg",
class:"text-red-500",
"Hello, 世界"
}
}
我们给 div
添加了 id
和 class
属性,对应的 HTML:
<div id="msg" class="text-red-500">
Hello, 世界
</div>
由此可知:rsx 的属性是键值对,多个属性需要用逗号分割。