Yew学习笔记

Yew是一个Rust/Wasm框架,用来创建前端页面。

基本web技术

使用html!宏可以写HTML,这个宏的内部会将其转化为代表DOM的Rust代码:

use yew::prelude::*;

let my_header: Html = html! {
    <img src="img_girl.jpg" alt="Girl in a jacket" width="500" height="600" />
};

html!中可以使用大括号来嵌入周围的变量

use yew::prelude::*;

let header_text = "Hello world".to_string();
let header_html: Html = html! {
    <h1>{header_text}</h1>
};

let count: usize = 5;
let counter_html: Html = html! {
    <p>{"My age is: "}{count}</p>
};

let combined_html: Html = html! {
    <div>{header_html}{counter_html}</div>
};

这个嵌入应该是移动语义,并且主要到可以嵌入其他Html

html!比较重要的一个规则是其内部只能有一个node,如果要写多个node需要使用fragments,就是没有name的那个tag,应该只是语法上的形式:

use yew::html;

// fixed: using html fragments
html! {
    <>
        <div></div>
        <p></p>
    </>
};

Rust要使用Javascript其实是Wasm与Javascript交互,因为Rust代码要编译成Wasm。Wasm与Javascript交互的基础是wasm-bindgen这个库,直接用wasm-bindgen还是太麻烦了,js-sysweb-sys两个crate可以简化使用,js-sys提供了对Javascript原生API的绑定,web-sys则提供web相关API的绑定。一个使用web-sys的例子如下:

// 对应的JS代码为let document = window.document

use wasm_bindgen::UnwrapThrowExt;
use web_sys::window;

let document = window()
    .expect_throw("window is undefined")
    .document()
    .expect_throw("document is undefined");

wasm-bindgen有一个很重要的地方是模拟JS中的继承的,这对使用web-sys也很重要。wasm-bindgen中使用Rust的DerefAsRef两个trait来模拟继承。比如C继承自B,B继承自A,则有:

  • C可以Deref成B
  • B可以Deref成A
  • C可以AsRefB和A
  • B可以AsRefA

这种实现可以使C以&B或者&A的身份使用其对应方法。另外所有的类型有一个基类JsValue。yew docs中有一个示例讲了从一个HtmlTextAreaElement一直derefJaValue的过程,我把英文注释翻译成中文:

use std::ops::Deref;
use web_sys::{
    Element,
    EventTarget,
    HtmlElement,
    HtmlTextAreaElement,
    Node,
};

fn inheritance_of_text_area(text_area: HtmlTextAreaElement) {
    // HtmlTextAreaElement在html就是一个