浏览代码

implement onmounted for the web renderer

Evan Almloff 2 年之前
父节点
当前提交
cb5cb56ad3
共有 2 个文件被更改,包括 48 次插入11 次删除
  1. 7 0
      packages/interpreter/src/sledgehammer_bindings.rs
  2. 41 11
      packages/web/src/dom.rs

+ 7 - 0
packages/interpreter/src/sledgehammer_bindings.rs

@@ -116,6 +116,10 @@ mod js {
     export function set_node(id, node) {
         nodes[id] = node;
     }
+    export function get_node(id) {
+        console.log(nodes, id);
+        return nodes[id];
+    }
     export function initilize(root, handler) {
         listeners.handler = handler;
         nodes = [root];
@@ -166,6 +170,9 @@ mod js {
         #[wasm_bindgen]
         pub fn set_node(id: u32, node: Node);
 
+        #[wasm_bindgen]
+        pub fn get_node(id: u32) -> Node;
+
         #[wasm_bindgen]
         pub fn initilize(root: Node, handler: &Function);
     }

+ 41 - 11
packages/web/src/dom.rs

@@ -10,8 +10,8 @@
 use dioxus_core::{
     BorrowedAttributeValue, ElementId, Mutation, Template, TemplateAttribute, TemplateNode,
 };
-use dioxus_html::{event_bubbles, CompositionData, FormData};
-use dioxus_interpreter_js::{save_template, Channel};
+use dioxus_html::{event_bubbles, CompositionData, FormData, MountedData};
+use dioxus_interpreter_js::{get_node, save_template, Channel};
 use futures_channel::mpsc;
 use rustc_hash::FxHashMap;
 use std::{any::Any, rc::Rc};
@@ -27,6 +27,7 @@ pub struct WebsysDom {
     templates: FxHashMap<String, u32>,
     max_template_id: u32,
     pub(crate) interpreter: Channel,
+    event_channel: mpsc::UnboundedSender<UiEvent>,
 }
 
 pub struct UiEvent {
@@ -34,7 +35,6 @@ pub struct UiEvent {
     pub bubbles: bool,
     pub element: ElementId,
     pub data: Rc<dyn Any>,
-    pub event: Event,
 }
 
 impl WebsysDom {
@@ -48,8 +48,9 @@ impl WebsysDom {
         };
         let interpreter = Channel::default();
 
-        let handler: Closure<dyn FnMut(&Event)> =
-            Closure::wrap(Box::new(move |event: &web_sys::Event| {
+        let handler: Closure<dyn FnMut(&Event)> = Closure::wrap(Box::new({
+            let event_channel = event_channel.clone();
+            move |event: &web_sys::Event| {
                 let name = event.type_();
                 let element = walk_event_for_id(event);
                 let bubbles = dioxus_html::event_bubbles(name.as_str());
@@ -69,10 +70,10 @@ impl WebsysDom {
                         bubbles,
                         element,
                         data,
-                        event: event.clone(),
                     });
                 }
-            }));
+            }
+        }));
 
         dioxus_interpreter_js::initilize(
             root.clone().unchecked_into(),
@@ -85,6 +86,7 @@ impl WebsysDom {
             interpreter,
             templates: FxHashMap::default(),
             max_template_id: 0,
+            event_channel,
         }
     }
 
@@ -156,6 +158,8 @@ impl WebsysDom {
     pub fn apply_edits(&mut self, mut edits: Vec<Mutation>) {
         use Mutation::*;
         let i = &mut self.interpreter;
+        // we need to apply the mount events last, so we collect them here
+        let mut to_mount = Vec::new();
         for edit in &edits {
             match edit {
                 AppendChildren { id, m } => i.append_children(id.0 as u32, *m as u32),
@@ -206,17 +210,43 @@ impl WebsysDom {
                 },
                 SetText { value, id } => i.set_text(id.0 as u32, value),
                 NewEventListener { name, id, .. } => {
-                    i.new_event_listener(name, id.0 as u32, event_bubbles(name) as u8);
-                }
-                RemoveEventListener { name, id } => {
-                    i.remove_event_listener(name, id.0 as u32, event_bubbles(name) as u8)
+                    match *name {
+                        // mounted events are fired immediately after the element is mounted.
+                        "mounted" => {
+                            to_mount.push(*id);
+                        }
+                        _ => {
+                            i.new_event_listener(name, id.0 as u32, event_bubbles(name) as u8);
+                        }
+                    }
                 }
+                RemoveEventListener { name, id } => match *name {
+                    "mounted" => {}
+                    _ => {
+                        i.remove_event_listener(name, id.0 as u32, event_bubbles(name) as u8);
+                    }
+                },
                 Remove { id } => i.remove(id.0 as u32),
                 PushRoot { id } => i.push_root(id.0 as u32),
             }
         }
         edits.clear();
         i.flush();
+
+        for id in to_mount {
+            let node = get_node(id.0 as u32);
+            if let Some(element) = node.dyn_ref::<Element>() {
+                log::info!("mounted event fired: {}", id.0);
+                let data: MountedData = element.into();
+                let data = Rc::new(data);
+                let _ = self.event_channel.unbounded_send(UiEvent {
+                    name: "mounted".to_string(),
+                    bubbles: false,
+                    element: id,
+                    data,
+                });
+            }
+        }
     }
 }