Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rustで自作しながら学ぶ仮想DOM

yud0uhu
February 27, 2023

 Rustで自作しながら学ぶ仮想DOM

DOMDOMトークス #1
by Feb 27, 2023

yud0uhu

February 27, 2023
Tweet

More Decks by yud0uhu

Other Decks in Programming

Transcript

  1. DOMとはなにか:DOMツリー構造 < html > < head > < title >私のウェブサイト</

    title > </ head > < body > < h1 >ようこそ</ h1 > < p >これは私のウェブサイトです。</ p > </ body > </ html > 5 - ドキュメント(ルート) - html - 頭 - タイトル - "私のウェブサイト" - 体 - h1 - "いらっしゃいませ" -p - 「これは私のウェブサイトです。」
  2. 仮想DOMを自作する • DOM は、特定のプログラミング言語から独立し、文書の 構造表現を単一の一貫した API から利用できるように設 計されています。 ほとんどのウェブ開発者が JavaScript

    でしか DOM を使用しないとしても、この Python の例 が示すように、 DOM の実装はどの言語でも構築するこ とができます。 ◦ DOM の紹介 - Web API | MDN 10
  3. render pub fn virtual_dom_to_html (node: &ElementType) -> String { match

    node { ElementType::Text(text) => text.clone(), ElementType::Element(tag, attrs, children) => { let attrs_str = attrs . iter() . map(|(key, value)| 17 format!("{}=\"{}\"", key, value)) . collect::<Vec<_>>() . join(" "); let children_str = children . iter() . map(|child| virtual_dom_to_html (child)) . collect::<Vec<_>>() . join(""); format!("<{} {}>{}</{}>", tag, attrs_str, children_str, tag) } } }
  4. diff 20 pub fn update_dom(old: &VNode, new: &VNode) -> AppResponse

    { let mut diff = Vec::new(); let removed_nodes = find_removed_nodes (old, new); for removed_node in removed_nodes { diff.push(Diff::RemoveNode(removed_node.clone())); } let added_nodes = find_added_nodes (old, new); for added_node in added_nodes { diff.push(Diff::AddNode(added_node.clone())); } let html = virtual_dom_to_html (&new.element_type); for change in &diff { match change { Diff::AddNode(node) => println!("Added Node: {:?}", node), Diff::RemoveNode(node) => println!("Removed Node: {:?}", node), } } AppResponse { diff, html } }
  5. patch 22 fn find_added_nodes (old: &VNode, new: &VNode) -> Vec<VNode>

    { let mut added_nodes = Vec::new(); find_added_nodes_recursive (&old.element_type, &new.element_type, &mut added_nodes); added_nodes } fn find_added_nodes_recursive (old: &ElementType, new: &ElementType, added_nodes: &mut Vec<VNode>) { if old != new { if !new.is_empty_text_node () { added_nodes.push(VNode { element_type: new.clone(), }); } } else if let ElementType::Element(_, _, old_children) = old { if let ElementType::Element(_, _, new_children) = new { for (old_child, new_child) in old_children.iter().zip(new_children.iter()) { find_added_nodes_recursive (old_child, new_child, added_nodes); } } } }
  6. patch 23 fn find_removed_nodes (old: &VNode, new: &VNode) -> Vec<VNode>

    { let mut removed_nodes = Vec::new(); find_removed_nodes_recursive (&old.element_type, &new.element_type, &mut removed_nodes); removed_nodes } fn find_removed_nodes_recursive ( old: &ElementType, new: &ElementType, removed_nodes: &mut Vec<VNode>, ) { if old != new { if !old.is_empty_text_node () { removed_nodes.push(VNode { element_type: old.clone(), }); } } else if let ElementType::Element(_, _, old_children) = old { if let ElementType::Element(_, _, new_children) = new { for (old_child, new_child) in old_children.iter().zip(new_children.iter()) { find_removed_nodes_recursive (old_child, new_child, removed_nodes); } } } }