Selaa lähdekoodia

reimplement link click event handler prop

Adrian Wannenmacher 2 vuotta sitten
vanhempi
commit
18c7f9c056
1 muutettua tiedostoa jossa 46 lisäystä ja 6 poistoa
  1. 46 6
      packages/router/src/components/link.rs

+ 46 - 6
packages/router/src/components/link.rs

@@ -1,3 +1,5 @@
+use std::fmt::Debug;
+
 use dioxus::prelude::*;
 use dioxus_router_core::{navigation::NavigationTarget, RouterMessage};
 use log::error;
@@ -5,7 +7,7 @@ use log::error;
 use crate::utils::use_router_internal::use_router_internal;
 
 /// The properties for a [`Link`].
-#[derive(Debug, Props)]
+#[derive(Props)]
 pub struct LinkProps<'a> {
     /// A class to apply to the generate HTML anchor tag if the `target` route is active.
     pub active_class: Option<&'a str>,
@@ -28,6 +30,16 @@ pub struct LinkProps<'a> {
     /// This does not change whether the [`Link`] is active or not.
     #[props(default)]
     pub new_tab: bool,
+    /// The onclick event handler.
+    pub onclick: Option<EventHandler<'a, MouseEvent>>,
+    #[props(default)]
+    /// Whether the default behavior should be executed if an `onclick` handler is provided.
+    ///
+    /// 1. When `onclick` is [`None`] (default if not specified), `onclick_only` has no effect.
+    /// 2. If `onclick_only` is [`false`] (default if not specified), the provided `onclick` handler
+    ///    will be executed after the links regular functionality.
+    /// 3. If `onclick_only` is [`true`], only the provided `onclick` handler will be executed.
+    pub onclick_only: bool,
     /// The rel attribute for the generated HTML anchor tag.
     ///
     /// For external `target`s, this defaults to `noopener noreferrer`.
@@ -37,6 +49,23 @@ pub struct LinkProps<'a> {
     pub target: NavigationTarget,
 }
 
+impl Debug for LinkProps<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("LinkProps")
+            .field("active_class", &self.active_class)
+            .field("children", &self.children)
+            .field("class", &self.class)
+            .field("exact", &self.exact)
+            .field("id", &self.id)
+            .field("new_tab", &self.new_tab)
+            .field("onclick", &self.onclick.as_ref().map(|_| "onclick is set"))
+            .field("onclick_only", &self.onclick_only)
+            .field("rel", &self.rel)
+            .field("target", &self.target)
+            .finish()
+    }
+}
+
 /// A link to navigate to another route.
 ///
 /// Only works as descendant of a component calling [`use_router`], otherwise it will be inactive.
@@ -109,6 +138,8 @@ pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element {
         exact,
         id,
         new_tab,
+        onclick,
+        onclick_only,
         rel,
         target,
     } = cx.props;
@@ -152,13 +183,22 @@ pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element {
         .or_else(|| is_external.then_some("noopener noreferrer"))
         .unwrap_or_default();
 
+    let do_default = onclick.is_none() || !onclick_only;
+    let action = move |event| {
+        if do_default {
+            if is_router_nav {
+                let _ = sender.unbounded_send(RouterMessage::Push(target.clone()));
+            }
+        }
+
+        if let Some(handler) = onclick {
+            handler.call(event);
+        }
+    };
+
     render! {
         a {
-            onclick: move |_| {
-                if is_router_nav {
-                    let _ = sender.unbounded_send(RouterMessage::Push(target.clone()));
-                }
-            },
+            onclick: action,
             href: "{href}",
             prevent_default: "{prevent_default}",
             class: "{class}",