Yew 是一個根據 Rust 和 WebAssembly 的前端框架,能建構高效能的網頁應用程式。本文以建構貓咪圖鑑為例,逐步講解如何使用 Yew 開發前端應用。首先,我們需要設定專案結構,包含使用 use_state hook 管理貓咪列表,並透過檔案輸入元件上傳圖片。接著,我們會實作 cat 函式,將貓咪資訊轉換為 HTML 並顯示,其中包含使用 base64 編碼顯示圖片。為了處理檔案上傳,我們會利用 gloo_file 和 wasm_bindgen_futures 進行非同步操作。最後,我們使用 stylist crate 來管理 CSS 樣式,並實作刪除貓咪圖片的功能,提升使用者經驗。
使用 Yew 和 WebAssembly 建立高效能網頁前端:貓咪圖鑑範例
本章節將介紹如何使用 Rust 語言的 Yew 框架和 WebAssembly 技術來建立一個高效能的網頁前端應用程式。我們將以建立一個貓咪圖鑑(Catdex)為例,逐步引導讀者完成整個開發過程。
專案初始設定與基本結構
首先,我們需要建立一個基本的 Yew 應用程式結構。這包括定義一個 App 元件函式,使用 use_state 這個 hook 來儲存目前的貓咪列表(CatDetails),並提供一個檔案輸入元件來上傳圖片。
use yew::prelude::*;
struct CatDetails {
name: String,
image: Vec<u8>,
}
fn app() -> Html {
let cat_list = use_state(|| vec![]);
let on_change = {
let cat_list = cat_list.clone();
move |e: Event| {
// 處理檔案上傳事件
}
};
html! {
<div>
<h1>{"Catdex"}</h1>
<input type="file" accept="image/*" onchange={on_change} />
<section class="cats">
{ for cat_list.iter().map(cat) }
</section>
</div>
}
}
fn cat(file: &CatDetails) -> Html {
// 將 CatDetails 轉換為 HTML
}
fn main() {
yew::Renderer::<App>::new().render();
}
內容解密:
use_statehook 用於儲存和管理貓咪列表的狀態。on_change事件處理器負責處理檔案上傳事件,並更新貓咪列表。html!巨集用於定義元件的 HTML 結構。
貓咪資訊的顯示
接下來,我們需要實作 cat 函式,將 CatDetails 轉換為 HTML,並顯示貓咪的名稱和圖片。為了顯示圖片,我們需要將圖片資料進行 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>
}
}
內容解密:
- 使用
base64crate 將圖片資料進行 base64 編碼。 - 將編碼後的圖片資料嵌入到
img標籤的src屬性中。
檔案上傳處理
為了處理檔案上傳,我們需要實作 on_change 事件處理器。這個處理器會讀取上傳的檔案,並將其轉換為 CatDetails 物件,然後更新貓咪列表。
use gloo_file::File;
use wasm_bindgen_futures::spawn_local;
use web_sys::{FileList, HtmlInputElement};
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());
// 處理上傳的檔案
})
}
};
內容解密:
- 使用
gloo_file和wasm_bindgen_futurescrate 來處理檔案上傳。 - 將上傳的檔案轉換為
CatDetails物件,並更新貓咪列表。
CSS 樣式設計
最後,我們需要為我們的應用程式新增 CSS 樣式,以改善其視覺效果。我們可以使用 stylist crate 來整合 CSS 樣式到我們的 Yew 元件中。
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>
}
}
內容解密:
- 使用
stylistcrate 來整合 CSS 樣式到 Yew 元件中。 - 將 CSS 樣式套用到元件的根元素上。
在 Rust 中使用 Yew 框架建立高效能 Web 前端
替換元件樣式
在我們的 Rust 程式碼中,我們已將 function_component 替換為 styled_component。接著,我們使用 (include_str!) 巨集從 src 資料夾載入 index.css,並將此字串轉換為樣式表。最後,為頂層的 div 提供此樣式表作為類別屬性。這些相對簡單的步驟使任何元件都能擁有自己的樣式,並且父元件能夠以正常層疊方式將樣式套用到子元件。你可以在圖 4-8 中看到這些新增樣式表的結果。
CSS 程式碼範例
.cats {
display: flex;
}
.cat {
border: 1px solid grey;
min-width: 200px;
min-height: 350px;
margin: 5px;
padding: 5px;
text-align: center;
}
.cat > img {
width: 190px;
}
內容解密:
.cats類別使用display: flex;將貓的列表以彈性盒子方式顯示,使其能夠自動調整排列。.cat類別為每個貓的專案設定邊框、最小寬度、最小高度、邊距和內距,使其在頁面上呈現良好的間距和對齊。.cat > img選擇器針對.cat內的圖片設定寬度,確保圖片在設定的範圍內正確顯示。
刪除檔案功能實作
目前的頁面設計存在一個明顯問題:可以新增貓到頁面,但無法刪除已新增的貓。是時候來修復這個問題了。
首先,我們需要在頂層的 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);
})
};
內容解密:
- 建立一個名為
delete_cat的回呼函式,並複製cat_list以在閉包中使用。 - 當回呼函式被觸發時,它會根據提供的名稱過濾出需要保留的貓,並更新
cat_list狀態。 - 這樣,當使用者點選刪除按鈕時,可以正確地從列表中移除指定的貓。
新增刪除按鈕元件
接下來,你需要一個按鈕元件來觸發這個回呼函式。
Rust 程式碼範例
#[derive(Properties, PartialEq)]
struct ButtonProp {
text: String,
name: String,
on_click: Callback<String>
}
#[function_component(Button)]
fn delete_button(button: &ButtonProp) -> Html {
let on_click = {
let name = button.name.clone();
let callback = button.on_click.clone();
move |_| {
callback.emit(name.clone())
}
};
html! {
<div>
<button onclick={on_click}>
{ button.text.clone() }
</button>
</div>
}
}
內容解密:
- 定義了一個名為
ButtonProp的結構體,用於傳遞按鈕的屬性,如文字、名稱和點選回呼函式。 - 建立了一個名為
Button的功能元件,用於渲染一個按鈕。 - 當按鈕被點選時,會觸發傳入的回呼函式,並傳遞按鈕相關的名稱。
修改 Cat 元件以支援刪除功能
fn cat(cat: &CatDetails, callback: Callback<String>) -> Html {
html! {
<article class="cat">
<h3>{ format!( "{}", cat.name )}</h3>
<Button text={"Delete".to_string()}
name={cat.name.clone()}
on_click={callback}
/>
<img src={format!("data:image;base64,{}",
general_purpose::STANDARD.encode(&cat.image))} />
</article>
}
}
內容解密:
- 修改了
cat元件,使其接受一個回呼函式,並將其傳遞給Button元件。 - 當點選刪除按鈕時,會觸發回呼函式,從而刪除對應的貓。
WebAssembly 替代方案
WebAssembly 是一個多功能的平台,因此有許多不同的工具和框架專注於不同的主題。本章介紹的工具大多由 Rust 和 WebAssembly 工作組維護。
其他前端框架
- Darco:受 Elm 和 Redux 啟發。
- Percy:支援同構 Web 應用程式,即相同的程式碼在伺服器端和客戶端執行。
- Seed:受 Elm、React 和 Redux 啟發。
- Smithy:另一個根據 Rust 的 WebAssembly 前端框架。
這些框架大多受到其他語言中流行的前端框架和模式的啟發,為開發者提供了多樣化的選擇。
使用 Rust 建構高效能的 WebAssembly 前端與 REST API 後端
WebAssembly 與 Rust 的結合
WebAssembly(Wasm)是一種二進位制指令格式,允許開發者在瀏覽器中執行高效能的程式碼。Rust 語言因其安全性和效能優勢,成為了開發 Wasm 模組的理想選擇。本章節將介紹如何使用 Rust 編譯至 Wasm,並在 Web 前端中使用。
使用 Rust 開發 WebAssembly 模組
Rust 提供了多種工具和函式庫來簡化 Wasm 模組的開發流程。以下是一個簡單的範例,展示如何使用 Rust 編譯至 Wasm,並在瀏覽器中執行:
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
pub fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
內容解密:
此範例程式碼使用了 wasm_bindgen 函式庫來產生與 JavaScript 的介面。#[wasm_bindgen] 屬性用於標記需要匯出至 JavaScript 的函式。greet 函式接受一個字串引數,並呼叫瀏覽器的 alert 函式來顯示問候訊息。
在前端中使用 WebAssembly
將 Rust 編譯至 Wasm 後,可以在前端專案中使用。以下是一個簡單的範例,展示如何使用 JavaScript 來載入和執行 Wasm 模組:
import * as wasm from './your_wasm_module';
wasm.greet('World');
內容解密:
此範例程式碼展示瞭如何使用 JavaScript 來匯入和執行 Wasm 模組。greet 函式是由 Rust 編譯至 Wasm 的函式,可以在 JavaScript 中直接呼叫。
使用 Yew 框架開發前端應用
Yew 是一個使用 Rust 和 Wasm 開發前端應用的框架。以下是一個簡單的範例,展示如何使用 Yew 來建立一個可以載入、顯示和刪除貓圖片的前端應用:
use yew::prelude::*;
enum Msg {
AddCat,
RemoveCat,
}
struct App {
cats: Vec<String>,
}
impl Component for App {
type Message = Msg;
type Properties = ();
fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
Self { cats: vec![] }
}
fn update(&mut self, msg: Self::Message) -> ShouldRender {
match msg {
Msg::AddCat => {
self.cats.push("new cat".to_string());
true
}
Msg::RemoveCat => {
self.cats.pop();
true
}
}
}
fn change(&mut self, _: Self::Properties) -> ShouldRender {
false
}
fn view(&self) -> Html {
html! {
<div>
<button onclick=self.link.callback(|_| Msg::AddCat)>{ "Add Cat" }</button>
<button onclick=self.link.callback(|_| Msg::RemoveCat)>{ "Remove Cat" }</button>
<ul>
{ for self.cats.iter().map(|cat| html! { <li>{ cat }</li> }) }
</ul>
</div>
}
}
}
內容解密:
此範例程式碼展示瞭如何使用 Yew 框架來建立一個前端應用。App 結構體代表了應用的狀態,update 方法處理了訊息,view 方法產生了 HTML。
建構 REST API 後端
Rust 也可用於建構高效能的 REST API 後端。以下是一個簡單的範例,展示如何使用 Rust 和 actix-web 框架來建立一個 REST API:
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
async fn index() -> impl Responder {
HttpResponse::Ok().body("Hello, World!")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/", web::get().to(index))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
內容解密:
此範例程式碼展示瞭如何使用 actix-web 框架來建立一個 REST API。index 函式處理了根路徑的 GET 請求,main 函式啟動了 HTTP 伺服器。