From 3d8efbe2738b5b88418710e03d256d429fa16c61 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Mon, 15 Apr 2024 22:43:07 +0800 Subject: [PATCH 1/3] feat: thaw_utils adds get_scroll_parent --- thaw_components/src/binder/mod.rs | 94 +++++-------------------- thaw_utils/src/dom/get_scroll_parent.rs | 55 +++++++++++++++ thaw_utils/src/dom/mod.rs | 5 ++ thaw_utils/src/{ => dom}/mount_style.rs | 0 thaw_utils/src/lib.rs | 4 +- 5 files changed, 80 insertions(+), 78 deletions(-) create mode 100644 thaw_utils/src/dom/get_scroll_parent.rs create mode 100644 thaw_utils/src/dom/mod.rs rename thaw_utils/src/{ => dom}/mount_style.rs (100%) diff --git a/thaw_components/src/binder/mod.rs b/thaw_components/src/binder/mod.rs index d19c7202..fa5ed6d2 100644 --- a/thaw_components/src/binder/mod.rs +++ b/thaw_components/src/binder/mod.rs @@ -4,12 +4,10 @@ pub use get_placement_style::FollowerPlacement; use crate::Teleport; use get_placement_style::{get_follower_placement_offset, FollowerPlacementOffset}; -use leptos::{ - html::{AnyElement, ElementDescriptor, ToHtmlElement}, - leptos_dom::helpers::WindowListenerHandle, - *, +use leptos::{html::ElementDescriptor, leptos_dom::helpers::WindowListenerHandle, *}; +use thaw_utils::{ + add_event_listener, get_scroll_parent, mount_style, with_hydration_off, EventListenerHandle, }; -use thaw_utils::{add_event_listener, mount_style, with_hydration_off, EventListenerHandle}; #[slot] pub struct Follower { @@ -74,26 +72,26 @@ pub fn Binder( let resize_handle = store_value(None::); let ensure_scroll_listener = move || { - let mut cursor = target_ref.get_untracked().map(|target| target.into_any()); - let mut scrollable_element_vec = vec![]; + let Some(el) = target_ref.get_untracked().map(|target| target.into_any()) else { + return; + }; + + let mut handle_vec = vec![]; + let mut cursor = get_scroll_parent(&el); loop { - cursor = get_scroll_parent(cursor); - if let Some(cursor) = cursor.take() { - scrollable_element_vec.push(cursor); + if let Some(el) = cursor.take() { + cursor = get_scroll_parent(&el); + + let handle = add_event_listener(el, ev::scroll, move |_| { + if let Some(scroll_listener) = scroll_listener.get_value() { + scroll_listener.call(()); + } + }); + handle_vec.push(handle); } else { break; } } - let handle_vec = scrollable_element_vec - .into_iter() - .map(|ele| { - add_event_listener(ele, ev::scroll, move |_| { - if let Some(scroll_listener) = scroll_listener.get_value() { - scroll_listener.call(()); - } - }) - }) - .collect(); scrollable_element_handle_vec.set_value(handle_vec); }; @@ -241,59 +239,3 @@ fn FollowerContainer( view! { } } - -fn get_scroll_parent(element: Option>) -> Option> { - let Some(element) = element else { - return None; - }; - - fn get_parent_element(element: HtmlElement) -> Option> { - if element.node_type() == 9 { - None - } else { - element.parent_element().map(|ele| ele.to_leptos_element()) - } - } - let Some(parent_element) = get_parent_element(element) else { - return None; - }; - - if parent_element.node_type() == 9 { - return Some(parent_element); - } - - if parent_element.node_type() == 1 { - fn get_overflow( - parent_element: &HtmlElement, - ) -> Option<(String, String, String)> { - let Ok(Some(css_style_declaration)) = window().get_computed_style(parent_element) - else { - return None; - }; - let Ok(overflow) = css_style_declaration.get_property_value("overflow") else { - return None; - }; - let Ok(overflow_x) = css_style_declaration.get_property_value("overflowX") else { - return None; - }; - let Ok(overflow_y) = css_style_declaration.get_property_value("overflowY") else { - return None; - }; - Some((overflow, overflow_x, overflow_y)) - } - if let Some((overflow, overflow_x, overflow_y)) = get_overflow(&parent_element) { - let overflow = format!("{overflow}{overflow_x}{overflow_y}"); - if overflow.contains("auto") { - return Some(parent_element); - } - if overflow.contains("scroll") { - return Some(parent_element); - } - if overflow.contains("overlay") { - return Some(parent_element); - } - } - } - - get_scroll_parent(Some(parent_element)) -} diff --git a/thaw_utils/src/dom/get_scroll_parent.rs b/thaw_utils/src/dom/get_scroll_parent.rs new file mode 100644 index 00000000..29dd9d61 --- /dev/null +++ b/thaw_utils/src/dom/get_scroll_parent.rs @@ -0,0 +1,55 @@ +use leptos::{ + html::{AnyElement, ToHtmlElement}, + *, +}; + +pub fn get_scroll_parent(element: &HtmlElement) -> Option> { + let Some(parent_element) = get_parent_element(element) else { + return None; + }; + + if parent_element.node_type() == 9 { + return Some(parent_element); + } + + if parent_element.node_type() == 1 { + if let Some((overflow, overflow_x, overflow_y)) = get_overflow(&parent_element) { + let overflow = format!("{overflow}{overflow_x}{overflow_y}"); + if overflow.contains("auto") { + return Some(parent_element); + } + if overflow.contains("scroll") { + return Some(parent_element); + } + if overflow.contains("overlay") { + return Some(parent_element); + } + } + } + + get_scroll_parent(&parent_element) +} + +fn get_parent_element(element: &HtmlElement) -> Option> { + if element.node_type() == 9 { + None + } else { + element.parent_element().map(|ele| ele.to_leptos_element()) + } +} + +fn get_overflow(parent_element: &HtmlElement) -> Option<(String, String, String)> { + let Ok(Some(css_style_declaration)) = window().get_computed_style(parent_element) else { + return None; + }; + let Ok(overflow) = css_style_declaration.get_property_value("overflow") else { + return None; + }; + let Ok(overflow_x) = css_style_declaration.get_property_value("overflowX") else { + return None; + }; + let Ok(overflow_y) = css_style_declaration.get_property_value("overflowY") else { + return None; + }; + Some((overflow, overflow_x, overflow_y)) +} diff --git a/thaw_utils/src/dom/mod.rs b/thaw_utils/src/dom/mod.rs new file mode 100644 index 00000000..d1fc0b62 --- /dev/null +++ b/thaw_utils/src/dom/mod.rs @@ -0,0 +1,5 @@ +mod get_scroll_parent; +mod mount_style; + +pub use get_scroll_parent::get_scroll_parent; +pub use mount_style::mount_style; diff --git a/thaw_utils/src/mount_style.rs b/thaw_utils/src/dom/mount_style.rs similarity index 100% rename from thaw_utils/src/mount_style.rs rename to thaw_utils/src/dom/mount_style.rs diff --git a/thaw_utils/src/lib.rs b/thaw_utils/src/lib.rs index 2edc3f5c..80c8d29a 100644 --- a/thaw_utils/src/lib.rs +++ b/thaw_utils/src/lib.rs @@ -1,14 +1,14 @@ pub mod class_list; +mod dom; mod event_listener; mod hooks; -mod mount_style; mod optional_prop; mod signals; mod time; +pub use dom::{get_scroll_parent, mount_style}; pub use event_listener::{add_event_listener, EventListenerHandle}; pub use hooks::{use_click_position, use_lock_html_scroll, use_next_frame, NextFrame}; -pub use mount_style::mount_style; pub use optional_prop::OptionalProp; pub use signals::{ create_component_ref, ComponentRef, Model, OptionalMaybeSignal, SignalWatch, StoredMaybeSignal, From fc309cb0ae7a4fafbef338957c7dcdda519d49ef Mon Sep 17 00:00:00 2001 From: luoxiao Date: Tue, 16 Apr 2024 16:36:11 +0800 Subject: [PATCH 2/3] feat: add BackTop --- demo/src/app.rs | 1 + demo/src/pages/components.rs | 4 ++ demo_markdown/docs/back_top/mod.md | 12 ++++ demo_markdown/src/lib.rs | 1 + thaw/Cargo.toml | 2 + thaw/src/back_top/back-top.css | 61 +++++++++++++++++ thaw/src/back_top/mod.rs | 103 +++++++++++++++++++++++++++++ thaw/src/back_top/theme.rs | 21 ++++++ thaw/src/lib.rs | 2 + thaw/src/theme/mod.rs | 12 ++-- 10 files changed, 215 insertions(+), 4 deletions(-) create mode 100644 demo_markdown/docs/back_top/mod.md create mode 100644 thaw/src/back_top/back-top.css create mode 100644 thaw/src/back_top/mod.rs create mode 100644 thaw/src/back_top/theme.rs diff --git a/demo/src/app.rs b/demo/src/app.rs index 4deb83b4..7a3cc269 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -49,6 +49,7 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { + diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 3f6af579..3855a592 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -208,6 +208,10 @@ pub(crate) fn gen_menu_data() -> Vec { MenuGroupOption { label: "Navigation Components".into(), children: vec![ + MenuItemOption { + value: "back-top".into(), + label: "Back Top".into(), + }, MenuItemOption { value: "breadcrumb".into(), label: "Breadcrumb".into(), diff --git a/demo_markdown/docs/back_top/mod.md b/demo_markdown/docs/back_top/mod.md new file mode 100644 index 00000000..95b99b1c --- /dev/null +++ b/demo_markdown/docs/back_top/mod.md @@ -0,0 +1,12 @@ +# Back Top + +BackTop will find its first scrollable ascendant element and listen scroll event on it. + +```rust demo +view! { + +} +``` + +
+
\ No newline at end of file diff --git a/demo_markdown/src/lib.rs b/demo_markdown/src/lib.rs index 78f378c1..700eabd1 100644 --- a/demo_markdown/src/lib.rs +++ b/demo_markdown/src/lib.rs @@ -31,6 +31,7 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt "AlertMdPage" => "../docs/alert/mod.md", "AutoCompleteMdPage" => "../docs/auto_complete/mod.md", "AvatarMdPage" => "../docs/avatar/mod.md", + "BackTopMdPage" => "../docs/back_top/mod.md", "BadgeMdPage" => "../docs/badge/mod.md", "BreadcrumbMdPage" => "../docs/breadcrumb/mod.md", "ButtonMdPage" => "../docs/button/mod.md", diff --git a/thaw/Cargo.toml b/thaw/Cargo.toml index 5944f32f..d6757ede 100644 --- a/thaw/Cargo.toml +++ b/thaw/Cargo.toml @@ -21,6 +21,8 @@ web-sys = { version = "0.3.69", features = [ "File", "FileList", "DataTransfer", + "ScrollToOptions", + "ScrollBehavior", ] } wasm-bindgen = "0.2.92" icondata_core = "0.1.0" diff --git a/thaw/src/back_top/back-top.css b/thaw/src/back_top/back-top.css new file mode 100644 index 00000000..eef377bf --- /dev/null +++ b/thaw/src/back_top/back-top.css @@ -0,0 +1,61 @@ +.thaw-back-top { + position: fixed; + right: 40px; + bottom: 40px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: color 0.3s cubic-bezier(0.4, 0, 0.2, 1), + box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1), + background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1); + border-radius: 22px; + height: 44px; + min-width: 44px; + box-shadow: 0 2px 8px 0px rgba(0, 0, 0, 0.12); + background-color: var(--thaw-background-color); +} + +.thaw-back-top.fade-in-scale-up-transition-leave-active { + transform-origin: inherit; + transition: opacity 0.2s cubic-bezier(0.4, 0, 1, 1), + transform 0.2s cubic-bezier(0.4, 0, 1, 1); +} + +.thaw-back-top.fade-in-scale-up-transition-enter-active { + transform-origin: inherit; + transition: opacity 0.2s cubic-bezier(0, 0, 0.2, 1), + transform 0.2s cubic-bezier(0, 0, 0.2, 1); +} + +.thaw-back-top.fade-in-scale-up-transition-enter-from, +.thaw-back-top.fade-in-scale-up-transition-leave-to { + opacity: 0; + transform: scale(0.9); +} + +.thaw-back-top.fade-in-scale-up-transition-leave-from, +.thaw-back-top.fade-in-scale-up-transition-enter-to { + opacity: 1; + transform: scale(1); +} + +.thaw-back-top > .thaw-icon { + transition: color 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.thaw-back-top:hover { + box-shadow: 0 2px 12px 0px #0000002e; +} + +.thaw-back-top:hover > .thaw-icon { + color: var(--thaw-icon-color-hover); +} + +.thaw-back-top:active { + box-shadow: 0 2px 12px 0px #0000002e; +} + +.thaw-back-top:active .thaw-icon { + color: var(--thaw-icon-color-active); +} diff --git a/thaw/src/back_top/mod.rs b/thaw/src/back_top/mod.rs new file mode 100644 index 00000000..93c149b8 --- /dev/null +++ b/thaw/src/back_top/mod.rs @@ -0,0 +1,103 @@ +mod theme; + +pub use theme::BackTopTheme; + +use crate::{use_theme, Icon, Theme}; +use leptos::{html::ToHtmlElement, *}; +use thaw_components::{CSSTransition, Teleport}; +use thaw_utils::{add_event_listener, get_scroll_parent, mount_style}; + +#[component] +pub fn BackTop( + #[prop(default=40.into(), into)] right: MaybeSignal, + #[prop(default=40.into(), into)] bottom: MaybeSignal, + #[prop(default=180.into(), into)] visibility_height: MaybeSignal, + #[prop(optional)] children: Option, +) -> impl IntoView { + mount_style("back-top", include_str!("./back-top.css")); + let theme = use_theme(Theme::light); + let style = Memo::new(move |_| { + let mut style = String::new(); + style.push_str(&format!("right: {}px;", right.get_untracked())); + style.push_str(&format!("bottom: {}px;", bottom.get_untracked())); + theme.with(|theme| { + style.push_str(&format!( + "--thaw-icon-color-hover: {};", + theme.common.color_primary_hover + )); + style.push_str(&format!( + "--thaw-icon-color-active: {};", + theme.common.color_primary_active + )); + style.push_str(&format!( + "--thaw-background-color: {};", + theme.back_top.background_color + )); + }); + style + }); + let placeholder_ref = NodeRef::::new(); + let back_top_ref = NodeRef::new(); + let is_show_back_top = RwSignal::new(false); + let scroll_top = RwSignal::new(0); + + let _ = watch( + move || scroll_top.get(), + move |scroll_top, _, _| { + is_show_back_top.set(scroll_top > &visibility_height.get()); + }, + false, + ); + + let scroll_to_top = StoredValue::new(None::>); + + placeholder_ref.on_load(move |el| { + let scroll_el = get_scroll_parent(&el.into_any()) + .unwrap_or_else(|| document().document_element().unwrap().to_leptos_element()); + + { + let scroll_el = scroll_el.clone(); + scroll_to_top.set_value(Some(Callback::new(move |_| { + scroll_el.scroll_by_with_scroll_to_options( + web_sys::ScrollToOptions::new() + .top(0.0) + .behavior(web_sys::ScrollBehavior::Smooth), + ); + }))); + } + + let handle = add_event_listener(scroll_el.clone(), ev::scroll, move |_| { + scroll_top.set(scroll_el.scroll_top()); + }); + + on_cleanup(move || { + handle.remove(); + }); + }); + + let on_click = move |_| { + scroll_to_top.with_value(|scroll_to_top| { + if let Some(scroll_to_top) = scroll_to_top { + scroll_to_top.call(()); + } + }); + }; + + view! { + + } +} diff --git a/thaw/src/back_top/theme.rs b/thaw/src/back_top/theme.rs new file mode 100644 index 00000000..10cec496 --- /dev/null +++ b/thaw/src/back_top/theme.rs @@ -0,0 +1,21 @@ +use crate::theme::ThemeMethod; + +#[derive(Clone)] +pub struct BackTopTheme { + pub background_color: String, + +} + +impl ThemeMethod for BackTopTheme { + fn light() -> Self { + Self { + background_color: "#fff".into(), + } + } + + fn dark() -> Self { + Self { + background_color: "#48484e".into(), + } + } +} diff --git a/thaw/src/lib.rs b/thaw/src/lib.rs index 733c9ff1..cd06dd64 100644 --- a/thaw/src/lib.rs +++ b/thaw/src/lib.rs @@ -1,6 +1,7 @@ mod alert; mod auto_complete; mod avatar; +mod back_top; mod badge; mod breadcrumb; mod button; @@ -46,6 +47,7 @@ mod upload; pub use alert::*; pub use auto_complete::*; pub use avatar::*; +pub use back_top::*; pub use badge::*; pub use breadcrumb::*; pub use button::*; diff --git a/thaw/src/theme/mod.rs b/thaw/src/theme/mod.rs index 9e42b82b..602d8571 100644 --- a/thaw/src/theme/mod.rs +++ b/thaw/src/theme/mod.rs @@ -3,10 +3,11 @@ mod common; use self::common::CommonTheme; use crate::{ mobile::{NavBarTheme, TabbarTheme}, - AlertTheme, AutoCompleteTheme, AvatarTheme, BreadcrumbTheme, ButtonTheme, CalendarTheme, - CollapseTheme, ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme, MessageTheme, - PopoverTheme, ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, SliderTheme, - SpinnerTheme, SwitchTheme, TableTheme, TagTheme, TimePickerTheme, TypographyTheme, UploadTheme, + AlertTheme, AutoCompleteTheme, AvatarTheme, BackTopTheme, BreadcrumbTheme, ButtonTheme, + CalendarTheme, CollapseTheme, ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme, + MessageTheme, PopoverTheme, ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, + SliderTheme, SpinnerTheme, SwitchTheme, TableTheme, TagTheme, TimePickerTheme, TypographyTheme, + UploadTheme, }; use leptos::*; @@ -46,6 +47,7 @@ pub struct Theme { pub popover: PopoverTheme, pub collapse: CollapseTheme, pub scrollbar: ScrollbarTheme, + pub back_top: BackTopTheme, } impl Theme { @@ -80,6 +82,7 @@ impl Theme { popover: PopoverTheme::light(), collapse: CollapseTheme::light(), scrollbar: ScrollbarTheme::light(), + back_top: BackTopTheme::light(), } } pub fn dark() -> Self { @@ -113,6 +116,7 @@ impl Theme { popover: PopoverTheme::dark(), collapse: CollapseTheme::dark(), scrollbar: ScrollbarTheme::dark(), + back_top: BackTopTheme::dark(), } } } From a6e64f52ecc3270620f9053f27ba5735291e5749 Mon Sep 17 00:00:00 2001 From: luoxiao Date: Tue, 16 Apr 2024 17:42:23 +0800 Subject: [PATCH 3/3] feat: BackTop scroll --- demo_markdown/docs/back_top/mod.md | 38 ++++++++++++++++- thaw/src/back_top/back-top.css | 9 ++--- thaw/src/back_top/mod.rs | 65 ++++++++++++++++++++---------- 3 files changed, 84 insertions(+), 28 deletions(-) diff --git a/demo_markdown/docs/back_top/mod.md b/demo_markdown/docs/back_top/mod.md index 95b99b1c..3778a9b0 100644 --- a/demo_markdown/docs/back_top/mod.md +++ b/demo_markdown/docs/back_top/mod.md @@ -8,5 +8,39 @@ view! { } ``` -
-
\ No newline at end of file +### Visibility height + +```rust demo +view! { + +
+ "Visibility Height: 280px" +
+
+} +``` + +### Change position + +```rust demo +view! { + +
+ "Change Position" +
+
+} +``` + +### BackTop Props + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| class | `OptionalProp>` | `Default::default()` | Addtional classes for the back top element. | +| right | `MaybeSignal` | `40` | The width of BackTop from the right side of the page. | +| bottom | `MaybeSignal` | `40` | The height of BackTop from the bottom of the page. | +| bottom | `MaybeSignal` | `180` | BackTop's trigger scroll top. | +| children | `Option` | `None` | BackTop's content. | + +
+
diff --git a/thaw/src/back_top/back-top.css b/thaw/src/back_top/back-top.css index eef377bf..5bbc165f 100644 --- a/thaw/src/back_top/back-top.css +++ b/thaw/src/back_top/back-top.css @@ -1,7 +1,5 @@ .thaw-back-top { position: fixed; - right: 40px; - bottom: 40px; cursor: pointer; display: flex; align-items: center; @@ -40,7 +38,8 @@ transform: scale(1); } -.thaw-back-top > .thaw-icon { +.thaw-back-top > svg { + font-size: 24px; transition: color 0.3s cubic-bezier(0.4, 0, 0.2, 1); } @@ -48,7 +47,7 @@ box-shadow: 0 2px 12px 0px #0000002e; } -.thaw-back-top:hover > .thaw-icon { +.thaw-back-top:hover > svg { color: var(--thaw-icon-color-hover); } @@ -56,6 +55,6 @@ box-shadow: 0 2px 12px 0px #0000002e; } -.thaw-back-top:active .thaw-icon { +.thaw-back-top:active svg { color: var(--thaw-icon-color-active); } diff --git a/thaw/src/back_top/mod.rs b/thaw/src/back_top/mod.rs index 93c149b8..639b8800 100644 --- a/thaw/src/back_top/mod.rs +++ b/thaw/src/back_top/mod.rs @@ -4,11 +4,14 @@ pub use theme::BackTopTheme; use crate::{use_theme, Icon, Theme}; use leptos::{html::ToHtmlElement, *}; -use thaw_components::{CSSTransition, Teleport}; -use thaw_utils::{add_event_listener, get_scroll_parent, mount_style}; +use thaw_components::{CSSTransition, Fallback, OptionComp, Teleport}; +use thaw_utils::{ + add_event_listener, class_list, get_scroll_parent, mount_style, EventListenerHandle, OptionalProp, +}; #[component] pub fn BackTop( + #[prop(optional, into)] class: OptionalProp>, #[prop(default=40.into(), into)] right: MaybeSignal, #[prop(default=40.into(), into)] bottom: MaybeSignal, #[prop(default=180.into(), into)] visibility_height: MaybeSignal, @@ -37,7 +40,7 @@ pub fn BackTop( style }); let placeholder_ref = NodeRef::::new(); - let back_top_ref = NodeRef::new(); + let back_top_ref = NodeRef::::new(); let is_show_back_top = RwSignal::new(false); let scroll_top = RwSignal::new(0); @@ -50,28 +53,36 @@ pub fn BackTop( ); let scroll_to_top = StoredValue::new(None::>); + let scroll_handle = StoredValue::new(None::); placeholder_ref.on_load(move |el| { - let scroll_el = get_scroll_parent(&el.into_any()) - .unwrap_or_else(|| document().document_element().unwrap().to_leptos_element()); + request_animation_frame(move || { + let scroll_el = get_scroll_parent(&el.into_any()) + .unwrap_or_else(|| document().document_element().unwrap().to_leptos_element()); - { - let scroll_el = scroll_el.clone(); - scroll_to_top.set_value(Some(Callback::new(move |_| { - scroll_el.scroll_by_with_scroll_to_options( - web_sys::ScrollToOptions::new() - .top(0.0) - .behavior(web_sys::ScrollBehavior::Smooth), - ); - }))); - } + { + let scroll_el = scroll_el.clone(); + scroll_to_top.set_value(Some(Callback::new(move |_| { + scroll_el.scroll_to_with_scroll_to_options( + web_sys::ScrollToOptions::new() + .top(0.0) + .behavior(web_sys::ScrollBehavior::Smooth), + ); + }))); + } - let handle = add_event_listener(scroll_el.clone(), ev::scroll, move |_| { - scroll_top.set(scroll_el.scroll_top()); + let handle = add_event_listener(scroll_el.clone(), ev::scroll, move |_| { + scroll_top.set(scroll_el.scroll_top()); + }); + scroll_handle.set_value(Some(handle)); }); + }); - on_cleanup(move || { - handle.remove(); + on_cleanup(move || { + scroll_handle.update_value(|handle| { + if let Some(handle) = handle.take() { + handle.remove(); + } }); }); @@ -93,8 +104,20 @@ pub fn BackTop( show=is_show_back_top let:display > -
- +
+ + + + + {children()} +