euv_ui/component/virtual_list/view/
fn.rs1use crate::*;
2
3#[component]
17pub fn euv_virtual_list(node: VirtualNode<EuvVirtualListProps>) -> VirtualNode {
18 let EuvVirtualListProps {
19 config,
20 item_renderer,
21 on_scroll,
22 on_visible_range_change,
23 } = node.try_get_props().unwrap_or_default();
24 let state: UseVirtualList = UseVirtualList::use_scroll_state();
25 let container_id: String = config.id.clone();
26 let total_count: usize = config.total_count;
27 let item_height: i32 = config.item_height;
28 let overscan_count: usize = config.overscan_count;
29 let viewport_height: i32 = state.get_viewport_height().get();
30 if viewport_height == 0 {
31 state.schedule_measure_by_id(&container_id);
32 }
33 let scroll_handler: Option<Rc<dyn Fn(Event)>> = {
34 let state: UseVirtualList = state;
35 let container_id: String = container_id.clone();
36 let on_scroll: Option<VirtualListScrollHandler> = on_scroll;
37 Some(Rc::new(move |_: Event| {
38 if let Some(element) = UseVirtualList::try_get_container_by_id(&container_id) {
39 let html_element: HtmlElement = element.unchecked_into();
40 let scroll_offset: i32 = html_element.scroll_top();
41 state.get_scroll_offset().set(scroll_offset);
42 if let Some(ref callback) = on_scroll {
43 callback(scroll_offset);
44 }
45 }
46 }))
47 };
48 let scroll_offset: i32 = state.get_scroll_offset().get();
49 let (_, _, render_start, render_end): (usize, usize, usize, usize) =
50 UseVirtualList::compute_visible_range(
51 scroll_offset,
52 viewport_height,
53 total_count,
54 item_height,
55 overscan_count,
56 );
57 let range_callback: Option<VirtualListRangeHandler> = on_visible_range_change.clone();
58 let range_watch_initialized: Signal<bool> = App::use_signal(|| false);
59 if !range_watch_initialized.get() {
60 let scroll_offset_signal: Signal<i32> = state.get_scroll_offset();
61 let viewport_height_signal: Signal<i32> = state.get_viewport_height();
62 let fire_handle: FireHandle = (move || {
63 let scroll_offset: i32 = scroll_offset_signal.get();
64 let viewport_height: i32 = viewport_height_signal.get();
65 if let Some(ref callback) = range_callback {
66 let (visible_start, visible_end, _, _): (usize, usize, usize, usize) =
67 UseVirtualList::compute_visible_range(
68 scroll_offset,
69 viewport_height,
70 total_count,
71 item_height,
72 overscan_count,
73 );
74 callback((visible_start, visible_end));
75 }
76 })
77 .into();
78 App::batch(|| {
79 scroll_offset_signal.subscribe(move || {
80 App::batch(|| unsafe { fire_handle.fire() });
81 });
82 viewport_height_signal.subscribe(move || {
83 App::batch(|| unsafe { fire_handle.fire() });
84 });
85 unsafe { fire_handle.fire() }
86 range_watch_initialized.set(true);
87 });
88 }
89 let total_height: i32 = total_count as i32 * item_height;
90 let top_padding: i32 = render_start as i32 * item_height;
91 let children: Vec<VirtualNode> = (render_start..render_end)
92 .map(|index: usize| {
93 let item_node: VirtualNode = (item_renderer)(index);
94 html! {
95 div {
96 key: index.to_string()
97 style: format!("height: {item_height}px; box-sizing: border-box;")
98 item_node
99 }
100 }
101 })
102 .collect();
103 html! {
104 div {
105 class: c_virtual_list_container()
106 id: container_id
107 onscroll: scroll_handler
108 div {
109 style: format!("position: relative; height: {total_height}px;")
110 div {
111 style: format!("position: absolute; top: {top_padding}px; left: 0; right: 0;")
112 children
113 }
114 }
115 }
116 }
117}