1use web_sys::HtmlDivElement;
2use yew::prelude::*;
3
4static mut RENDER_LIST: Vec<Html> = Vec::new();
5
6#[derive(Debug, Clone, PartialEq, Properties)]
7pub struct Props {
8 pub request: Option<Callback<(usize, Callback<Html>)>>,
12 pub children: Option<Children>,
13 pub is_direction_row: Option<bool>,
14}
15
16#[function_component(InfiniteFor)]
72pub fn infinite_for(props: &Props) -> Html {
73 let request = props
74 .request
75 .clone()
76 .unwrap_or(Callback::from(|i: (usize, Callback<Html>)| {
77 i.1.emit(html!(
78 <div
79 style="\
80 min-height: 300px;\
81 min-width: 700px;\
82 height: 300px;\
83 width: 700px;\
84 border-radius: 5px;\
85 background-color: rgba(222, 240, 255, 0.262);\
86 margin: 5px;\
87 "
88 >
89 <h1>{i.0}</h1>
90 </div>
91 ))
92 }));
93
94 let loading_block = props.children.clone();
95 let request_number_state = use_state(|| 0usize);
96 let request_times_state = use_state(|| 0usize);
97 let list_state = use_state(|| html!(<></>));
98 let is_bottom_state = use_state(|| true);
99
100 let is_direction_row = props.is_direction_row;
101 let list_ref = NodeRef::default();
102 let loading_block_ref = NodeRef::default();
103
104 let list_push = {
105 Callback::from(move |item: Html| unsafe {
106 RENDER_LIST.push(item);
107 })
108 };
109
110 {
111 let list_ref = list_ref.clone();
112 let request = request.clone();
113 let list_push = list_push.clone();
114 let list_state = list_state.clone();
115 let request_number_state = request_number_state.clone();
116 let request_times_state = request_times_state.clone();
117
118 use_effect(move || {
119 let list_ref = list_ref.cast::<HtmlDivElement>().unwrap();
120
121 if list_ref.scroll_height() - 100 < list_ref.client_height()
122 && list_ref.scroll_width() - 100 < list_ref.client_width()
123 {
124 request_number_state.set(*request_number_state + 1);
125 request_times_state.set(*request_times_state + 1);
126
127 let key = *request_times_state;
128
129 request.emit((key, list_push));
130 unsafe {
131 list_state.set(
132 RENDER_LIST
133 .clone()
134 .into_iter()
135 .enumerate()
136 .map(|(key, i)| html!(<div {key}>{i}</div>))
137 .collect(),
138 )
139 }
140 }
141 || ()
142 })
143 };
144
145 let onscroll = {
146 let list_ref = list_ref.clone();
147 let loading_block_ref = loading_block_ref.clone();
148 let is_bottom_state = is_bottom_state.clone();
149
150 let list_push = list_push.clone();
151 let request = request.clone();
152 let list_state = list_state.clone();
153 let request_number_state = request_number_state.clone();
154 let request_times_state = request_times_state.clone();
155
156 Callback::from(move |_| {
157 let list_ref = list_ref.cast::<HtmlDivElement>().unwrap();
158 let list_pos = (list_ref.scroll_left(), list_ref.scroll_top());
159
160 let refresh_range = loading_block_ref.cast::<HtmlDivElement>().unwrap();
161
162 let refresh_range = if is_direction_row.unwrap_or(false) {
163 refresh_range.scroll_width()
164 } else {
165 refresh_range.scroll_height()
166 };
167
168 let befor_is_bottom_state = *is_bottom_state;
169
170 let after_is_bottom_state = match (
171 is_direction_row,
172 list_ref.scroll_width() - list_pos.0 - list_ref.client_width() <= refresh_range,
173 list_ref.scroll_height() - list_pos.1 - list_ref.client_height() <= refresh_range,
174 ) {
175 (Some(true), true, _) | (None, _, true) | (Some(false), _, true) => true,
176 _ => false,
177 };
178
179 if !befor_is_bottom_state && after_is_bottom_state {
180 request_times_state.set(*request_times_state + *request_number_state);
181
182 for i in 0..*request_number_state {
183 let key = *request_times_state + i;
184
185 request.emit((key, list_push.clone()));
186 unsafe {
187 list_state.set(
188 RENDER_LIST
189 .clone()
190 .into_iter()
191 .enumerate()
192 .map(|(key, i)| html!(<div {key}>{i}</div>))
193 .collect(),
194 )
195 }
196 }
197 }
198
199 list_ref.scroll_to_with_x_and_y(list_pos.0 as f64, list_pos.1 as f64);
200
201 is_bottom_state.set(after_is_bottom_state);
202 })
203 };
204
205 html! {
206 <>
207 <div
208 ref={list_ref}
209 {onscroll}
210 style={
211 format!("\
212 height: 100%;\
213 width: 100%;\
214 margin-bottom: 5px;\
215 display: flex;\
216 justify-content: flex-start;\
217 align-items: center;\
218 flex-direction: {};\
219 overflow: auto;\
220 ",
221 if is_direction_row == Some(true) {"row"}
222 else {"column"})
223 }
224 >
225 {(*list_state).clone()}
227 <div
229 ref={loading_block_ref}
230 style="\
231 width: auto;\
232 height: auto;\
233 "
234 >
235 {
236 if let Some(loading_block) = loading_block {
237 loading_block
238 } else {
239 Children::new(vec![html!(
240 <h4
241 style="\
242 background: rgb(18,23,46);\
243 padding: 5px;\
244 border-radius: 5px;\
245 "
246 >
247 {"到底了"}
248 </h4>
249 )])
250 }
251 }
252 </div>
253 </div>
254 </>
255 }
256}