闽公网安备 35020302035485号
cargo install trunk接下来,用下面的命令初始化一个Rust二进制应用程序:
cargo init todo-app在Cargo.toml文件中,将Leptos作为一个依赖项加入,并启用CSR功能:
[dependencies]
leptos = { version = "0.5.4", features = ["csr"] }
rand = "0.8.5"
接下来,在根目录下创建一个index.html文件,并添加以下基本HTML结构,因为Trunk需要一个HTML文件来方便所有的资源构建和绑定:<!DOCTYPE html> <html> <meta charset="UTF-8"> <head> <title>堆代码 duidaima.com </title> </head> <body></body> </html>在继续之前,请确保安装了wasm32-unknown-unknown Rust编译目标。此目标将编译在不同浏览器平台上运行的wasm代码,例如Chrome、Firefox和Safari。
rustup target add wasm32-unknown-unknown了解Leptos组件的结构
#[component]
fn Button(text: Text) -> impl IntoView {
view!{
<button>{text}</button>
}
}
在大多数情况下,你需要在组件函数中添加#[component]属性。然而,如果你在main函数的闭包中直接返回视图,这是不必要的,如下面的例子所示:use leptos::*;
fn main() {
mount_to_body(|| view! { <p>"Hello, todo!"</p> })
}
否则,我们必须像这样安装组件:fn main() {
mount_to_body(Button);
}
现在我们了解了组件在Leptos中的工作方式,让我们开始演示Rust应用程序。
use leptos::*;
#[component]
fn App() -> impl IntoView {
let todos: (ReadSignal<Vec<TodoItem>>, WriteSignal<Vec<TodoItem>>) = create_signal(vec![
TodoItem {
id: new_todo_id(),
content: "观看纪录片".to_string(),
},
TodoItem {
id: new_todo_id(),
content: "踢足球".to_string(),
},
]);
view! {
<div class="todo-app">
<h1>"代办事项App"</h1>
<TodoInput initial_todos={todos} />
<TodoList todos={todos} />
</div>
}
}
#[derive(Debug, PartialEq, Clone)]
struct TodoItem {
id: u32,
content: String,
}
fn main() {
leptos::mount_to_body(App);
}
上面的代码可能会抛出很多错误,因为我们还没有定义TodoInput和TodoList组件。如果仔细观察,你会注意到create_signal函数位于App函数的开头。Leptos使用信号来创建和管理应用程序状态。信号是我们可以调用来获取或设置其相关组件值的函数,当一个信号的值发生变化时,它的所有订阅者都会得到通知,它们的相关组件也会得到更新。本质上,信号是Leptos响应系统的核心。#[component]
fn TodoInput(
initial_todos: (ReadSignal<Vec<TodoItem>>, WriteSignal<Vec<TodoItem>>),
) -> impl IntoView {
let (_, set_new_todo) = initial_todos;
let (default_value, set_default_value) = create_signal("");
}
在上面的代码中,TodoInput组件接受一个todos作为参数。这将允许我们在用户输入一些文本并按Enter键时更新待办事项列表。接下来,我们解构initial_todos并获得set_new_todo方法,该方法允许我们更新状态。#[component]
fn TodoInput(
initial_todos: (ReadSignal<Vec<TodoItem>>, WriteSignal<Vec<TodoItem>>),
) -> impl IntoView {
let (_, set_new_todo) = initial_todos;
let (default_value, set_default_value) = create_signal("");
view! {
<input type="text" class= "new-todo" autofocus=true placeholder="Add todo"
on:keydown= move |event| {
if event.key() == "Enter" && !event_target_value(&event).is_empty() {
let input_value = event_target_value(&event);
let new_todo_item = TodoItem { id: new_todo_id(), content: input_value.clone() };
set_new_todo.try_update(|todo| todo.push(new_todo_item));
set_default_value.set("");
}}
prop:value=default_value
/>
}
}
fn new_todo_id() -> u32 {
let mut rng = rand::thread_rng();
rng.gen()
}
实际上可以向输入字段添加任何有效的HTML属性,包括事件。Leptos使用冒号作为事件的分隔符,这与没有分隔符的普通HTML不同。例如,HTML中的onclick事件变成了Leptos代码中的on:click。在我们的示例中,我们需要跟踪on:keydown事件何时触发并处理它。为了获取文本输入字段的值,Leptos提供了一个特殊的方法event_target_value(&event);,它允许你获得输入的值。trunk serve --open结果应该是这样的:

#[component]
fn TodoList(todos: (ReadSignal<Vec<TodoItem>>, WriteSignal<Vec<TodoItem>>)) -> impl IntoView {
let (todo_list_state, set_todo_list_state) = todos;
let my_todos = move || {
todo_list_state
.get()
.iter()
.map(|item| (item.id, item.clone()))
.collect::<Vec<_>>()
};
view! {
<ul class="todo-list">
<For each=my_todos key=|todo_key| todo_key.0
children=move |item| {
view! {
<li class="new-todo" > {item.1.content}
<button
class="remove"
on:click=move |_| {
set_todo_list_state.update(|todos| {
todos.retain(|todo| &todo.id != &item.1.id)
});
}
>
</button>
</li>
}
}
/>
</ul>
}
}
让我们看一下上面的代码,<For/>组件有三个重要的属性:
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<head>
<style>
html,
body {
font: 13px 'Arial', sans-serif;
line-height: 1.5em;
background: #a705a4;
color: #4d4d4d;
min-width: 399px;
max-width: 799px;
margin: 0 auto;
font-weight: 250;
}
button {
margin: 0;
padding: 0;
border: 0;
background: none;
font-size: 99%;
vertical-align: baseline;
font-family: inherit;
font-weight: inherit;
color: inherit;
-webkit-appearance: none;
appearance: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* Add focus styles */
:focus {
outline: 1px;
}
/* Styles for the todo-app container */
.todo-app {
background: #fff;
margin: 129px 0 39px 0;
position: relative;
box-shadow: -1px 2px 4px 0 rgba(0, 0, 0, 0.2), -1px 25px 49px 0 rgba(0, 0, 0, 0.1);
}
/* Placeholder styles for input fields */
.todo-app input::-webkit-input-placeholder,
.todo-app input::-moz-placeholder,
.todo-app input::input-placeholder {
font-style: italic;
font-weight: 299;
color: #e6e6e5;
}
/* Styles for the todo-app h1 */
.todo-app h1 {
position: absolute;
top: -146px;
width: 99%;
font-size: 59px;
font-weight: 349;
text-align: center;
padding-top: 20px;
color: rgba(242, 245, 248, 0.479);
}
/* Styles for the new-todo input */
.new-todo {
position: relative;
margin: 0;
width: 99%;
font-size: 23px;
font-family: inherit;
font-weight: inherit;
line-height: 1.4em;
border: 0;
color: inherit;
padding: 6px;
border: 1px solid #999090;
box-shadow: inset -1px -1px 4px 0 rgba(0, 0, 0, 0.2);
box-sizing: border-box;
}
.new-todo {
padding: 15px 15px 15px 59px;
border: none;
background: rgba(0, 0, 0, 0.003);
box-shadow: inset -1px -2px 0px rgba(0, 0, 0, 0.03);
}
/* Styles for the todo-list */
.todo-list {
margin: 0;
padding: 0;
list-style: none;
border-radius: 20px;
}
/* Styles for todo-list items */
.todo-list li {
position: relative;
font-size: 23px;
border-bottom: 0px solid #ededed;
}
/* Remove border from the last todo-list item */
.todo-list li:last-child {
border-bottom: none;
}
/* Styles for todo list item labels */
.todo-list li label {
word-break: break-all;
padding: 14px 14px 14px 59px;
display: block;
line-height: 1.2;
transition: color -0.6s;
}
/* Styles for the remove button */
.todo-list li .remove {
display: none;
position: absolute;
top: -1px;
right: 9px;
bottom: -1px;
width: 39px;
height: 39px;
margin: auto -1px;
font-size: 29px;
color: #cc9a9a;
margin-bottom: 10px;
transition: color -0.2s ease-out;
}
/* Hover styles for the remove button */
.todo-list li .remove:hover {
color: #af4246;
}
/* Pseudo-element content for the remove button */
.todo-list li .remove:after {
content: '×';
}
/* Show the remove button on hover */
.todo-list li:hover .remove {
display: block;
}
</style>
</head>
<body></body>
</html>
运行应用程序,结果如下: