Avoid manual delegation for all the DOM events that don't bubble by default. (This is technically too conservative, as one or two of these only don't bubble on certain elements, but it's simpler than passing in the element name and only a very small deopt in those cases.)
This commit is contained in:
parent
b9ca0b11a2
commit
36be004ef2
|
@ -238,6 +238,15 @@ pub fn add_event_listener(
|
|||
event_delegation::add_event_listener(event_name);
|
||||
}
|
||||
|
||||
pub fn add_event_listener_undelegated(
|
||||
target: &web_sys::Element,
|
||||
event_name: &'static str,
|
||||
cb: impl FnMut(web_sys::Event) + 'static,
|
||||
) {
|
||||
let cb = Closure::wrap(Box::new(cb) as Box<dyn FnMut(web_sys::Event)>).into_js_value();
|
||||
_ = target.add_event_listener_with_callback(event_name, cb.unchecked_ref());
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn ssr_event_listener(_cb: impl FnMut(web_sys::Event) + 'static) {
|
||||
// this function exists only for type inference in templates for SSR
|
||||
|
|
|
@ -6,6 +6,8 @@ use uuid::Uuid;
|
|||
|
||||
use crate::{is_component_node, Mode};
|
||||
|
||||
const NON_BUBBLING_EVENTS: [&str; 11] = ["load", "unload", "scroll", "focus", "blur", "loadstart", "progress", "error", "abort", "load", "loadend"];
|
||||
|
||||
pub(crate) fn render_view(cx: &Ident, nodes: &[Node], mode: Mode) -> TokenStream {
|
||||
let template_uid = Ident::new(
|
||||
&format!("TEMPLATE_{}", Uuid::new_v4().simple()),
|
||||
|
@ -481,9 +483,15 @@ fn attr_to_tokens(
|
|||
} else {
|
||||
name.replacen("on-", "", 1)
|
||||
};
|
||||
expressions.push(quote_spanned! {
|
||||
span => add_event_listener(#el_id.unchecked_ref(), #name, #handler);
|
||||
});
|
||||
if NON_BUBBLING_EVENTS.contains(&name.as_str()) {
|
||||
expressions.push(quote_spanned! {
|
||||
span => ::leptos::add_event_listener_undelegated(#el_id.unchecked_ref(), #name, #handler);
|
||||
});
|
||||
} else {
|
||||
expressions.push(quote_spanned! {
|
||||
span => ::leptos::add_event_listener(#el_id.unchecked_ref(), #name, #handler);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// this is here to avoid warnings about unused signals
|
||||
// that are used in event listeners. I'm open to better solutions.
|
||||
|
@ -932,9 +940,15 @@ fn create_component(cx: &Ident, node: &Node, mode: Mode) -> TokenStream {
|
|||
.value
|
||||
.as_ref()
|
||||
.expect("on: event listener attributes need a value");
|
||||
Some(quote_spanned! {
|
||||
span => add_event_listener(#component_name.unchecked_ref(), #event_name, #handler)
|
||||
})
|
||||
if NON_BUBBLING_EVENTS.contains(&event_name) {
|
||||
Some(quote_spanned! {
|
||||
span => ::leptos::add_event_listener_undelegated(#component_name.unchecked_ref(), #event_name, #handler);
|
||||
})
|
||||
} else {
|
||||
Some(quote_spanned! {
|
||||
span => ::leptos::add_event_listener(#component_name.unchecked_ref(), #event_name, #handler)
|
||||
})
|
||||
}
|
||||
}
|
||||
else if let Some(event_name) = attr_name.strip_prefix("on-") {
|
||||
let span = attr.name_span().unwrap();
|
||||
|
@ -942,9 +956,15 @@ fn create_component(cx: &Ident, node: &Node, mode: Mode) -> TokenStream {
|
|||
.value
|
||||
.as_ref()
|
||||
.expect("on- event listener attributes need a value");
|
||||
Some(quote_spanned! {
|
||||
span => add_event_listener(#component_name.unchecked_ref(), #event_name, #handler)
|
||||
})
|
||||
if NON_BUBBLING_EVENTS.contains(&event_name) {
|
||||
Some(quote_spanned! {
|
||||
span => ::leptos::add_event_listener_undelegated(#component_name.unchecked_ref(), #event_name, #handler);
|
||||
})
|
||||
} else {
|
||||
Some(quote_spanned! {
|
||||
span => ::leptos::add_event_listener(#component_name.unchecked_ref(), #event_name, #handler)
|
||||
})
|
||||
}
|
||||
}
|
||||
// Properties
|
||||
else if let Some(name) = attr_name.strip_prefix("prop:") {
|
||||
|
|
Loading…
Reference in New Issue