123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- //! Virtual Node Support
- //!
- //! VNodes represent lazily-constructed VDom trees that support diffing and event handlers. These VNodes should be *very*
- //! cheap and *very* fast to construct - building a full tree should be quick.
- use std::fmt::{Debug, Formatter};
- mod arbitrary_value;
- mod component;
- mod element;
- mod factory;
- mod fragment;
- mod placeholder;
- mod suspense;
- mod template;
- mod text;
- pub use arbitrary_value::*;
- pub use component::*;
- pub use element::*;
- pub use factory::*;
- pub use fragment::*;
- pub use suspense::*;
- pub use template::*;
- pub use text::*;
- use self::placeholder::VPlaceholder;
- /// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM.
- ///
- /// VNodes are designed to be lightweight and used with with a bump allocator. To create a VNode, you can use either of:
- ///
- /// - the `rsx!` macro
- /// - the [`NodeFactory`] API
- pub enum VNode<'src> {
- /// Text VNodes are simply bump-allocated (or static) string slices
- ///
- /// # Example
- ///
- /// ```rust, ignore
- /// let mut vdom = VirtualDom::new();
- /// let node = vdom.render_vnode(rsx!( "hello" ));
- ///
- /// if let VNode::Text(vtext) = node {
- /// assert_eq!(vtext.text, "hello");
- /// assert_eq!(vtext.dom_id.get(), None);
- /// assert_eq!(vtext.is_static, true);
- /// }
- /// ```
- Text(&'src VText<'src>),
- /// Element VNodes are VNodes that may contain attributes, listeners, a key, a tag, and children.
- ///
- /// # Example
- ///
- /// ```rust, ignore
- /// let mut vdom = VirtualDom::new();
- ///
- /// let node = vdom.render_vnode(rsx!{
- /// div {
- /// key: "a",
- /// onclick: |e| log::info!("clicked"),
- /// hidden: "true",
- /// style: { background_color: "red" },
- /// "hello"
- /// }
- /// });
- ///
- /// if let VNode::Element(velement) = node {
- /// assert_eq!(velement.tag_name, "div");
- /// assert_eq!(velement.namespace, None);
- /// assert_eq!(velement.key, Some("a"));
- /// }
- /// ```
- Element(&'src VElement<'src>),
- /// Fragment nodes may contain many VNodes without a single root.
- ///
- /// # Example
- ///
- /// ```rust, ignore
- /// rsx!{
- /// a {}
- /// link {}
- /// style {}
- /// "asd"
- /// Example {}
- /// }
- /// ```
- Fragment(&'src VFragment<'src>),
- /// Component nodes represent a mounted component with props, children, and a key.
- ///
- /// # Example
- ///
- /// ```rust, ignore
- /// fn Example(cx: Scope) -> Element {
- /// ...
- /// }
- ///
- /// let mut vdom = VirtualDom::new();
- ///
- /// let node = vdom.render_vnode(rsx!( Example {} ));
- ///
- /// if let VNode::Component(vcomp) = node {
- /// assert_eq!(vcomp.user_fc, Example as *const ());
- /// }
- /// ```
- Component(&'src VComponent<'src>),
- /// Templetes ase generated by the rsx macro to eleminate diffing static nodes.
- ///
- ///
- ///
- ///
- ///
- ///
- Template(&'src VTemplate<'src>),
- }
- /// An Element's unique identifier.
- ///
- /// `ElementId` is a `usize` that is unique across the entire VirtualDOM - but not unique across time. If a component is
- /// unmounted, then the `ElementId` will be reused for a new component.
- #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
- #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
- #[cfg_attr(feature = "serialize", serde(transparent))]
- pub struct ElementId(pub usize);
- impl<'src> VNode<'src> {
- /// Get the VNode's "key" used in the keyed diffing algorithm.
- pub fn key(&self) -> Option<&'src str> {
- match &self {
- VNode::Element(el) => el.key,
- VNode::Component(c) => c.key,
- VNode::Fragment(f) => f.key,
- VNode::Template(t) => t.key,
- VNode::Text(_t) => None,
- }
- }
- /// Get the ElementID of the mounted VNode.
- ///
- /// Panics if the mounted ID is None or if the VNode is not represented by a single Element.
- pub fn mounted_id(&self) -> ElementId {
- self.try_mounted_id().unwrap()
- }
- /// Try to get the ElementID of the mounted VNode.
- ///
- /// Returns None if the VNode is not mounted, or if the VNode cannot be presented by a mounted ID (Fragment/Component)
- pub fn try_mounted_id(&self) -> Option<ElementId> {
- match &self {
- VNode::Text(el) => el.id.get(),
- VNode::Element(el) => el.id.get(),
- VNode::Fragment(_) => None,
- VNode::Component(_) => None,
- VNode::Template(_) => None,
- }
- }
- // Create an "owned" version of the vnode.
- pub(crate) fn decouple(&self) -> VNode<'src> {
- match *self {
- VNode::Text(t) => VNode::Text(t),
- VNode::Element(e) => VNode::Element(e),
- VNode::Component(c) => VNode::Component(c),
- VNode::Fragment(f) => VNode::Fragment(f),
- VNode::Template(t) => VNode::Template(t),
- }
- }
- }
- impl Debug for VNode<'_> {
- fn fmt(&self, s: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
- match &self {
- VNode::Element(el) => s
- .debug_struct("VNode::Element")
- .field("name", &el.tag)
- .field("key", &el.key)
- .field("attrs", &el.attributes)
- .field("children", &el.children)
- .field("id", &el.id)
- .finish(),
- VNode::Text(t) => s
- .debug_struct("VNode::Text")
- .field("text", &t.text)
- .field("id", &t.id)
- .finish(),
- VNode::Fragment(frag) => s
- .debug_struct("VNode::Fragment")
- .field("children", &frag.children)
- .finish(),
- VNode::Component(comp) => s
- .debug_struct("VNode::Component")
- .field("name", &comp.fn_name)
- .field("fnptr", &comp.user_fc)
- .field("key", &comp.key)
- .field("scope", &comp.scope)
- .finish(),
- VNode::Template(temp) => s
- .debug_struct("VNode::Templates")
- .field("template_id", &temp.template.id)
- .finish(),
- }
- }
- }
|