Dioxus (Rustでfrontend) 入門2
RSX入門
基本的な書式
ドキュメントは下記にあります。
以下サンプル
rsx!(
div {
button {
onclick: move |e| todos.write().new_todo(),
"Add todo"
}
ul {
class: "todo-list",
todos.iter().map(|(key, todo)| rsx!(
li {
class: "beautiful-todo"
key: "f"
h3 { "{todo.title}" }
p { "{todo.contents}"}
}
))
}
}
)
<div>
<button onclick="XXX"> Add todo </button>
<ul class="todo-list">
<li class="beautiful-todo" key="f" >
<h3>$todo.title</h3>
<p> $todo.contents </p>
</li>
</div>
などと変換されます。 (繰り返しは省略ですw)
書式的に難しいところは特にありませんので、詳しい説明は省略させていただきます。
デフォルトで利用できるタグ
ここに列挙するとものすごい量になるので以下を参照してください。
利用可能なイベント
ここに列挙するとすごい量になるので以下を参照してください。
条件分岐
マニュアルには rsx内部で書く場合には thenを利用したものしか載っておりませんが、 ifもmatchも利用できます。
rsxの外に書く場合は公式マニュアルがわかりやすいのでそちらを参照してください。
match文をrsx内で利用したい!
{ match 10 {
10 => rsx!{"10!!"},
20 => rsx!{"20!!"},
_ => rsx!{"default!!"},
}}
if をrsx内で利用したい!
{if 1 == 2 { rsx!{"aaa"} } else { rsx!{"bbb"} }}
ループ
マニュアルはここです。
これに関して特に補足することはありませんが、 for文をrsx内で利用する方法を知りたいなら 続きを読んでください。
ul {
class: "todo-list",
todos.iter().map(|(key, todo)| rsx!(
li {
class: "beautiful-todo"
key: "f"
h3 { "{todo.title}" }
p { "{todo.contents}"}
}
))
}
このような感じで todos (Vec<Todo>) の中身をループで取り出せます。
通常の用途であれば iter().map で事足りますが、 なんとしても for文を使いたい場合(あまり想像できないですがw)
下記の様に書けば for文をrsx!内で利用できます。
{
let mut tmp: Vec<LazyNodes> = Vec::new();
for i in 0..10 {
let str = format!("counter: {}", i);
tmp.push(rsx!{ div{"{str}"}});
}
tmp
}
カスタムHTMLを入れるには
let custom_elem = LazyNodes::new(move |f| {
f.raw_element("hogege", None, &[], &[Attribute{name: "hoge", value: "moge", is_static: true,is_volatile:false, namespace:None}],&[],None)
});
などとすると
<hogege hoge="moge"></hoge>
というタグを作り出すことができる。 また、イベントリスナも足すことができるため、
rsxでは事前定義されていない属性やイベント・タグなども追加することができます。
生htmlタグを出力したい
div {
dangerous_inner_html: "<ul><li>aaa</li><li>bbb</li></ul>",
}
dangerous_inner_html属性に文字列を渡せばhtmlタグをそのままレンダリングすることができます。
ただクロスサイトスクリプティングに弱くなりますので、渡す内容は問題ないものに限定しなければなりません。
prevent_defaultでformによる自動ナビゲーションの停止
例えば下記のようなrsx!を考えてみます。
form {
onsubmit: move |e| {submit_event(e)},
oninput: move |ev:FormEvent| {onchange_ev(ev);},
input { r#type: "text", name: "username" }
input { r#type: "text", name: "full-name" }
input { r#type: "submit", value: "","aaa" }
}
このときsubmitボタンを押すと
http://localhost:8080/form_test?username=aaa&full-name=vvv
といった感じで現在のページに対してGETが走り、wasmやjsなどが再ロードされてしまいます。
それでは困るので、サブミットボタンをクリックしてもナビゲーションされないようにしてみます。
それには上記のrsxを下記のように書き直します。
form {
onsubmit: move |e| {submit_event(e)},
prevent_default: "onsubmit",
oninput: move |ev:FormEvent| {onchange_ev(ev);},
input { r#type: "text", name: "username" }
input { r#type: "text", name: "full-name" }
input { r#type: "submit", value: "","aaa" }
button { r#type: "submit", value: "submit"}
}
prevent_default: "onsubmit" prevent_defaultに 抑制したいイベント名を書きます。
そうすることで、自動ナビゲーションを無効にすることができます。
これによって、GETが走ることはなくなるため、 jsやwasmやcssなどが再ロードされることはなくなります。
ちなみに formのsubmitイベントを利用すると
let submit_event = move |ev: FormEvent| {
ev.cancel_bubble();
console::warn_1(&format!("Submitted {:?}", ev.values).into())
};
ev.valuesに Hash<String,String>
を得ることができます。キーは form内の intputタグのnameが入り、値にはvalueが入ります。
inputイベントではないので、submitした瞬間にvalidateを一気にかけたり、 Hash<String,String>から任意のstructに変換する TryFromなどを用意することで、変換することもできます。
また、入力ごとに再レンダリングが走ることもないため、それらが不要な場合には便利な方法です。
入力されるごとに、validateを走らせたい場合などでは、formの oninputイベントを利用することもできます。
Discussion