dioxus_bootstrap_css/
scrollspy.rs1use dioxus::prelude::*;
2
3#[derive(Clone, PartialEq, Props)]
22pub struct ScrollspyProps {
23 #[props(default = "body".to_string())]
25 pub target: String,
26 pub active: Signal<String>,
28 #[props(default = 0)]
30 pub offset: i32,
31}
32
33#[component]
34pub fn Scrollspy(props: ScrollspyProps) -> Element {
35 let mut active_signal = props.active;
36 let target = props.target.clone();
37 let offset = props.offset;
38
39 use_effect(move || {
41 let target = target.clone();
42 document::eval(&format!(
43 r#"
44 (function() {{
45 var container = document.querySelector('{target}');
46 if (!container || container === document.body) container = document;
47 var sections = document.querySelectorAll('[id]');
48 if (sections.length === 0) return;
49
50 function update() {{
51 var scrollTop = (container === document)
52 ? window.scrollY || document.documentElement.scrollTop
53 : container.scrollTop;
54 var offset = {offset};
55 var active = '';
56 sections.forEach(function(section) {{
57 var rect = section.getBoundingClientRect();
58 if (rect.top <= offset + 10) {{
59 active = section.id;
60 }}
61 }});
62 if (active && window.__dioxus_scrollspy_active !== active) {{
63 window.__dioxus_scrollspy_active = active;
64 // Dispatch a custom event that Dioxus can listen to
65 window.dispatchEvent(new CustomEvent('scrollspy', {{ detail: active }}));
66 }}
67 }}
68
69 var scrollTarget = (container === document) ? window : container;
70 scrollTarget.addEventListener('scroll', update, {{ passive: true }});
71 update();
72 }})();
73 "#
74 ));
75 });
76
77 use_effect(move || {
81 let eval_handle = document::eval(
82 r#"
83 (function() {
84 return new Promise(function(resolve) {
85 var current = window.__dioxus_scrollspy_active || '';
86 // Set up listener for changes
87 window.addEventListener('scrollspy', function handler(e) {
88 resolve(e.detail);
89 window.removeEventListener('scrollspy', handler);
90 });
91 // If already set, resolve immediately
92 if (current) resolve(current);
93 });
94 })()
95 "#,
96 );
97
98 spawn(async move {
99 if let Ok(value) = eval_handle.await {
100 if let Some(id) = value.as_str() {
101 active_signal.set(id.to_string());
102 }
103 }
104 });
105 });
106
107 rsx! {}
108}