diff --git a/xilem_web/Cargo.toml b/xilem_web/Cargo.toml index 00db6482e..92bcbc599 100644 --- a/xilem_web/Cargo.toml +++ b/xilem_web/Cargo.toml @@ -31,6 +31,7 @@ features = [ "console", "CssStyleDeclaration", "Document", + "DocumentFragment", "DomTokenList", "Element", "Event", diff --git a/xilem_web/src/context.rs b/xilem_web/src/context.rs index 597827bc9..5d2bcadb7 100644 --- a/xilem_web/src/context.rs +++ b/xilem_web/src/context.rs @@ -25,10 +25,20 @@ impl MessageThunk { } /// The [`View`](`crate::core::View`) `Context` which is used for all [`DomView`](`crate::DomView`)s -#[derive(Default)] pub struct ViewCtx { id_path: Vec, app_ref: Option>, + pub(crate) fragment: Rc, +} + +impl Default for ViewCtx { + fn default() -> Self { + ViewCtx { + id_path: Vec::default(), + app_ref: None, + fragment: Rc::new(crate::document().create_document_fragment()), + } + } } impl ViewCtx { diff --git a/xilem_web/src/elements.rs b/xilem_web/src/elements.rs index 94e7c8d5c..4c9b12812 100644 --- a/xilem_web/src/elements.rs +++ b/xilem_web/src/elements.rs @@ -3,8 +3,8 @@ //! Basic builder functions to create DOM elements, such as [`html::div`] -use std::any::Any; use std::borrow::Cow; +use std::{any::Any, rc::Rc}; use wasm_bindgen::{JsCast, UnwrapThrowExt}; use crate::{ @@ -135,6 +135,7 @@ pub struct DomChildrenSplice<'a, 'b, 'c, 'd> { children: VecSplice<'b, 'c, AnyPod>, ix: usize, parent: &'d web_sys::Node, + fragment: Rc, parent_was_removed: bool, } @@ -144,6 +145,7 @@ impl<'a, 'b, 'c, 'd> DomChildrenSplice<'a, 'b, 'c, 'd> { children: &'b mut Vec, vec_splice_scratch: &'c mut Vec, parent: &'d web_sys::Node, + fragment: Rc, parent_was_deleted: bool, ) -> Self { Self { @@ -151,6 +153,7 @@ impl<'a, 'b, 'c, 'd> DomChildrenSplice<'a, 'b, 'c, 'd> { children: VecSplice::new(children, vec_splice_scratch), ix: 0, parent, + fragment, parent_was_removed: parent_was_deleted, } } @@ -159,12 +162,20 @@ impl<'a, 'b, 'c, 'd> DomChildrenSplice<'a, 'b, 'c, 'd> { impl<'a, 'b, 'c, 'd> ElementSplice for DomChildrenSplice<'a, 'b, 'c, 'd> { fn with_scratch(&mut self, f: impl FnOnce(&mut AppendVec) -> R) -> R { let ret = f(self.scratch); - for element in self.scratch.drain() { + if !self.scratch.is_empty() { + for element in self.scratch.drain() { + self.fragment + .append_child(element.node.as_ref()) + .unwrap_throw(); + self.children.insert(element); + self.ix += 1; + } self.parent - .append_child(element.node.as_ref()) + .insert_before( + self.fragment.as_ref(), + self.children.next_mut().map(|p| p.node.as_ref()), + ) .unwrap_throw(); - self.children.insert(element); - self.ix += 1; } ret } @@ -262,6 +273,7 @@ where &mut element.props.children, &mut state.vec_splice_scratch, element.node.as_ref(), + ctx.fragment.clone(), element.was_removed, ); children.dyn_seq_rebuild( @@ -290,6 +302,7 @@ pub(crate) fn teardown_element( &mut element.props.children, &mut state.vec_splice_scratch, element.node.as_ref(), + ctx.fragment.clone(), true, ); children.dyn_seq_teardown(&mut state.seq_state, ctx, &mut dom_children_splice);