Yew 是一個根據 Rust 和 WebAssembly 的前端框架,提供類別似 React 的元件化開發模式,能有效提升 Web 應用程式的效能。本文將以建構 Catdex 應用程式為例,逐步說明如何使用 Yew 框架進行開發,包含圖片上傳、刪除及樣式設計等功能。我們將會探討 Yew 元件的生命週期、狀態管理、事件處理、檔案處理以及如何整合 CSS 樣式,讓讀者能快速掌握 Yew 框架的開發技巧,並應用於實際專案中。
使用 Yew 框架建立高效能 Web 前端應用程式
Yew 是目前最受歡迎的 WebAssembly 框架之一,其設計深受 React 和 Elm 的影響。瞭解這些框架有助於更好地掌握 Virtual DOM 和回應式架構的概念。
建立一個簡單的 Hello World 專案
首先,使用 Cargo 建立一個新的 Rust 專案,並新增 Yew 作為依賴。
$ cargo new hello-yew-world
$ cd hello-yew-world
$ cargo add yew --features csr
接著,更新 Cargo.toml 檔案以符合以下設定:
[package]
name = "yew-app"
version = "0.1.0"
edition = "2021"
[dependencies]
yew = { version = "0.20.0", features = ["csr"] }
內容解密:
cargo new hello-yew-world:建立一個新的 Rust 專案。cargo add yew --features csr:新增 Yew 作為依賴,並啟用csr功能。- 更新
Cargo.toml檔案:確保依賴版本正確。
編寫 Yew 應用程式
更新 main.rs 檔案如下:
use yew::prelude::*;
#[function_component(App)]
fn app() -> Html {
html! { <Button value=0/> }
}
#[derive(Properties, PartialEq)]
struct ButtonProp {
value: i64,
}
#[function_component(Button)]
fn increment_button(button: &ButtonProp) -> Html {
let counter = use_state(|| button.value);
let on_click = {
let counter = counter.clone();
move |_| {
let new_value = *counter + 1;
counter.set(new_value);
}
};
html! {
<div>
<button onclick={on_click}>{ "+1" }</button>
<p>{*counter}</p>
</div>
}
}
fn main() {
yew::Renderer::<App>::new().render();
}
內容解密:
#[function_component(App)]:定義一個名為App的函式元件。html! { <Button value=0/> }:使用html!巨集建立 HTML 節點。#[derive(Properties, PartialEq)]:為ButtonProp結構體匯出Properties和PartialEq特性。use_state:建立一個狀態鉤子(hook),用於儲存元件狀態。on_click:定義按鈕點選事件的處理函式。
建立 index.html 檔案
在專案根目錄下建立 index.html 檔案,內容如下:
<!DOCTYPE html>
<html lang="en">
<head></head>
<body></body>
</html>
內容解密:
- 建立一個基本的 HTML 檔案結構。
建置和執行專案
安裝 Trunk 工具,並使用它來建置和執行專案。
$ cargo install trunk
$ trunk serve --open
內容解密:
cargo install trunk:安裝 Trunk 工具。trunk serve --open:建置並執行專案,同時開啟瀏覽器存取http://127.0.0.1:8080。
Yew 元件的原理
Yew 的元件是透過函式定義的,傳回 Html 型別。元件的屬性透過結構體表示,並使用 Properties 特性進行標註。狀態管理透過 use_state 鉤子實作,當狀態更新時,Yew 會自動重新渲染相關元件。
此圖示說明瞭 Yew 元件的生命週期和狀態管理流程
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title Yew 框架構建高效能 Web 應用
package "Rust 記憶體管理" {
package "所有權系統" {
component [Owner] as owner
component [Borrower &T] as borrow
component [Mutable &mut T] as mutborrow
}
package "生命週期" {
component [Lifetime 'a] as lifetime
component [Static 'static] as static_lt
}
package "智慧指標" {
component [Box<T>] as box
component [Rc<T>] as rc
component [Arc<T>] as arc
component [RefCell<T>] as refcell
}
}
package "記憶體區域" {
component [Stack] as stack
component [Heap] as heap
}
owner --> borrow : 不可變借用
owner --> mutborrow : 可變借用
owner --> lifetime : 生命週期標註
box --> heap : 堆積分配
rc --> heap : 引用計數
arc --> heap : 原子引用計數
stack --> owner : 棧上分配
note right of owner
每個值只有一個所有者
所有者離開作用域時值被釋放
end note
@enduml
內容解密:
- 圖表展示了 Yew 元件的建立、屬性和狀態定義、事件處理以及重新渲染的流程。
使用 Yew 框架建立高效能 Web 前端應用程式
深入理解 Yew 的基礎元件與狀態管理
在前面的章節中,我們已經建立了一個簡單的計數器應用程式,展示了 Yew 的基本用法。現在,我們將進一步探討如何使用 Yew 建立一個更複雜的應用程式——一個貓咪索引(Catdex)。
貓咪索引(Catdex)應用程式的需求
我們的 Catdex 應用程式需要具備以下功能:
- 顯示貓咪列表
- 上傳新的貓咪資訊
- 刪除特定的貓咪資訊
這些功能將幫助我們瞭解如何在 Yew 中渲染列表、管理狀態以及在元件之間傳遞資料。
建立 Catdex 應用程式的基本結構
首先,讓我們建立一個新的 Cargo 專案並新增 Yew 依賴:
$ cargo new catdex-yew
$ cd catdex-yew
$ cargo add yew --features csr
接下來,我們需要建立一個 index.html 檔案,並在 src/main.rs 中定義我們的 App 元件:
use yew::prelude::*;
#[function_component(App)]
fn app() -> Html {
let cat_list = use_state(|| Vec::<CatDetails>::new());
let on_change = {
let cat_list = cat_list.clone();
// 稍後實作 on_change 回呼函式
};
html! {
<div>
<h1>{"Catdex"}</h1>
<input type="file" accept="image/*" onchange={on_change} />
<section class="cats">
{ for cat_list.iter().map(cat) }
</section>
</div>
}
}
#[derive(Clone)]
struct CatDetails {
name: String,
image: Vec<u8>,
}
fn cat(file: &CatDetails) -> Html {
// 稍後實作 cat 函式
}
fn main() {
yew::Renderer::<App>::new().render();
}
實作 cat 函式以顯示貓咪資訊
要顯示貓咪資訊,我們需要在 cat 函式中使用 base64 套件將圖片資料編碼為 base64 格式:
use base64::{engine::general_purpose, Engine};
fn cat(cat: &CatDetails) -> Html {
html! {
<article class="cat">
<h3>{ format!( "{}", cat.name )}</h3>
<img src={
format!("data:image;base64,{}",
general_purpose::STANDARD.encode(&cat.image))
} />
</article>
}
}
上傳檔案並儲存貓咪資訊
要上傳檔案並儲存貓咪資訊,我們需要使用 js-sys、gloo-file、wasm-bindgen-futures 和 web-sys 等套件。以下是一個範例程式碼,用於讀取上傳的檔案並更新 cat_list 狀態:
let on_change = {
let cat_list = cat_list.clone();
Callback::from(move |e: Event| {
let input: FileInput = e.target_unchecked_into();
if let Some(file) = input.files().and_then(|files| files.get(0)) {
let file_reader = FileReader::new().unwrap();
let file_reader_clone = file_reader.clone();
let cat_list_clone = cat_list.clone();
file_reader.onloadend = Some(move |_| {
let result = file_reader_clone.result().unwrap();
let bytes = result.dyn_into::<js_sys::Uint8Array>().unwrap().to_vec();
// 更新 cat_list 狀態
cat_list_clone.set(vec![CatDetails {
name: "新貓咪".to_string(),
image: bytes,
}]);
});
file_reader.read_as_array_buffer(&file).unwrap();
}
})
};
#### 內容解密:
在上述程式碼中,我們使用了 FileReader API 將上傳的檔案讀取為陣列緩衝區(Array Buffer),然後將其轉換為 Vec<u8> 以儲存貓咪的圖片資料。同時,我們更新了 cat_list 狀態以包含新的貓咪資訊。
高效能網頁前端開發:使用WebAssembly的實務解析
以Yew框架實作Catdex應用程式
本章節將探討如何利用Rust語言與Yew框架結合WebAssembly技術,開發高效能的網頁前端應用程式。我們將以一個名為Catdex的貓咪圖鑑應用程式為例,逐步介紹其開發過程與關鍵技術。
檔案上傳功能的實作
首先,我們需要實作檔案上傳功能,讓使用者可以上傳貓咪圖片至Catdex應用程式中。以下程式碼展示瞭如何使用gloo_file與wasm_bindgen_futures等crate來處理檔案上傳:
use std::ops::Deref;
use gloo_file::File;
use wasm_bindgen_futures::spawn_local;
use web_sys::{FileList, HtmlInputElement};
// 定義on_change事件處理函式
let on_change = {
let cat_list = cat_list.clone();
move |e: Event| {
let cat_list = cat_list.clone();
spawn_local(async move {
let input: HtmlInputElement = e.target_unchecked_into();
let files = upload_file(input.files());
let mut interior_cat_list = cat_list.deref().clone();
for file in files {
let new_details = CatDetails {
name: file.name(),
image: gloo_file::futures::read_as_bytes(&file).await.unwrap(),
};
interior_cat_list.push(new_details)
}
cat_list.set(interior_cat_list);
})
}
};
#### 內容解密:
1. **事件處理**: `on_change` 事件處理函式被定義為一個閉包,負責處理檔案上傳事件。
2. **檔案處理**: `upload_file` 函式負責將 `FileList` 轉換為 `Vec<File>`,以便於在Rust中處理。
3. **非同步處理**: 使用 `spawn_local` 來非同步處理檔案上傳,避免阻塞主執行緒。
4. **狀態更新**: 將新上傳的貓咪資料加入到 `cat_list` 中,並更新狀態。
#### 上傳檔案的輔助函式
```rust
fn upload_file(files: Option<FileList>) -> Vec<File> {
files
.map(|files| {
js_sys::try_iter(&files)
.unwrap()
.unwrap()
.map(|v| web_sys::File::from(v.unwrap()))
.map(File::from)
.collect()
})
.unwrap_or_default()
}
#### 內容解密:
1. **檔案列表處理**: `upload_file` 函式處理 `FileList` 並將其轉換為 `Vec<File>`。
2. **錯誤處理**: 使用 `unwrap` 與 `unwrap_or_default` 來處理可能的錯誤情況。
3. **檔案轉換**: 將 `web_sys::File` 轉換為 `gloo_file::File` 以便於在Rust中使用。
### CSS樣式設計
為了提升Catdex應用程式的視覺效果,我們需要加入CSS樣式。Yew框架本身不包含官方的CSS支援,但可以透過第三方crate如`stylist`來實作。
#### 使用stylist crate進行樣式設計
首先,新增`stylist` crate至專案中:
```bash
$ cargo add stylist --features yew
$ cargo add stylist --features parser
接著,在App元件中使用styled_component巨集來載入CSS樣式:
use stylist::{yew::styled_component, Style};
#[styled_component(App)]
fn app() -> Html {
const CSS: &str = include_str!("index.css");
let stylesheet = Style::new(CSS).unwrap();
// ...
html! {
<div class={stylesheet}>
// ...
</div>
}
}
#### 內容解密:
1. **樣式載入**: 使用 `include_str!` 巨集載入 `index.css` 檔案內容。
2. **樣式套用**: 將載入的CSS樣式套用到頂層 `div` 元素上。
3. **元件樣式化**: 使用 `styled_component` 巨集來標記 `App` 元件,使其支援樣式化。
### 刪除檔案功能實作
為了讓使用者可以刪除已上傳的貓咪圖片,我們需要在`App`元件中定義一個刪除貓咪的回呼函式。
#### 定義刪除貓咪的回呼函式
```rust
let delete_cat = {
let cat_list = cat_list.clone();
Callback::from(move |name: String| {
let interior_cat_list = cat_list.deref().clone();
let new_cat_list: Vec<_> = interior_cat_list
.into_iter()
.filter(|cat| cat.name != name)
.collect();
cat_list.set(new_cat_list);
})
};
#### 內容解密:
1. **回呼函式定義**: 定義一個刪除貓咪的回呼函式 `delete_cat`。
2. **狀態更新**: 根據提供的貓咪名稱,過濾掉對應的貓咪資料並更新 `cat_list` 狀態。
3. **回呼函式傳遞**: 將 `delete_cat` 回呼函式傳遞給 `cat` 元件,以便在需要時觸發刪除操作。
透過本章節的介紹,我們成功地使用Rust與Yew框架結合WebAssembly技術,實作了一個具備檔案上傳、CSS樣式設計與刪除檔案功能的高效能網頁前端應用程式Catdex。這不僅展示了WebAssembly在網頁前端開發中的強大潛力,也為開發者提供了一個實用的範例與參考。