|
109 | 109 | <body> |
110 | 110 | <scroll-viewport class="viewport"> |
111 | 111 | <!-- <header>some header content</header> --> |
| 112 | + <!-- onrenderrangechange="rangeChange(event,this)" --> |
112 | 113 | <fixed-size-virtual-list-s1 |
113 | 114 | id="l" |
114 | 115 | item-size="200" |
115 | 116 | item-count="1000000" |
116 | 117 | safe-area-inset-top="400" |
117 | 118 | safe-area-inset-bottom="100" |
118 | | - onrenderrangechange="rangeChange(event,this)" |
119 | 119 | > |
120 | 120 | <div class="block-card-item" slot="template"> |
121 | 121 | <div class="block-content"> |
|
144 | 144 | <button class="button" onclick="gotoTop()">go top</button> |
145 | 145 | </section> |
146 | 146 | </body> |
147 | | - <script> |
148 | | - const movingDuration = 200; |
149 | | - function rangeChange(event) { |
150 | | - const { entries, time } = event.detail; |
151 | | - for (const { node, index, stateInfoList, isIntersecting } of entries) { |
152 | | - const viewClass = event.target.className; |
153 | | - if (isIntersecting) { |
154 | | - // console.log("%s %c%s", viewClass, "color:green", type, index); |
155 | | - const height = l.itemCount - index; |
156 | | - const heightEle = node.querySelector("[name=height]"); |
157 | | - (heightEle.firstChild || heightEle).textContent = height; |
158 | | - const stateEle = node.querySelector("[name=state]"); |
159 | | - (stateEle.firstChild || stateEle).textContent = stateInfoList |
160 | | - .map( |
161 | | - (stateInfo) => |
162 | | - `${stateInfo.state}-${stateInfo.id}-${stateInfo.endTime.toFixed( |
163 | | - 2 |
164 | | - )}` |
165 | | - ) |
166 | | - .join("\n"); |
167 | | - { |
168 | | - let createScale = 0; |
169 | | - let createTime = 0; |
170 | | - let movingOffset = 0; |
171 | | - let movingTime = 0; |
172 | | - for (const stateInfo of stateInfoList) { |
173 | | - if (stateInfo.state === "moving") { |
174 | | - const diffTime = stateInfo.endTime - time; |
175 | | - movingOffset += (diffTime / movingDuration) * l.itemSize; |
176 | | - movingTime = Math.max(diffTime, movingTime); |
177 | | - } else if (stateInfo.state === "create") { |
178 | | - const diffTime = stateInfo.endTime - time; |
179 | | - createScale = diffTime / movingDuration; |
180 | | - createTime = diffTime; |
181 | | - } |
182 | | - } |
183 | | - |
184 | | - /**@TODO use replaceable animations */ |
185 | | - for (const ani of node.contentNode.getAnimations()) { |
186 | | - ani.cancel(); |
187 | | - } |
188 | | - const movingAniOptions = |
189 | | - movingOffset !== 0 && movingTime > 0 |
190 | | - ? { |
191 | | - from: -movingOffset, //`translateY(${-movingOffset}px)`, |
192 | | - to: 0, //`translateY(0px)`, |
193 | | - duration: movingTime, |
194 | | - } |
195 | | - : undefined; |
196 | | - const createAniOptions = |
197 | | - createScale !== 0 && createTime > 0 |
198 | | - ? { |
199 | | - from: 1 - createScale, //`scale(${1 - createScale})`, |
200 | | - to: 1, //`scale(1)`, |
201 | | - duration: createTime, |
202 | | - } |
203 | | - : undefined; |
204 | | - |
205 | | - if (movingAniOptions && createAniOptions) { |
206 | | - const framekeys = [ |
207 | | - { |
208 | | - transform: `translateY(${movingAniOptions.from}px) scale(${createAniOptions.from})`, |
209 | | - offset: 0, |
210 | | - }, |
211 | | - ]; |
212 | | - let aniDuration; |
213 | | - if (createAniOptions.duration > movingAniOptions.duration) { |
214 | | - aniDuration = createAniOptions.duration; |
215 | | - const offset = movingAniOptions.duration / aniDuration; |
216 | | - framekeys.push( |
217 | | - { |
218 | | - transform: `translateY(${movingAniOptions.to}px) scale(${ |
219 | | - createAniOptions.from + |
220 | | - (createAniOptions.to - createAniOptions.from) * offset |
221 | | - })`, |
222 | | - offset: offset, |
223 | | - }, |
224 | | - { |
225 | | - transform: `scale(${createAniOptions.to})`, |
226 | | - offset: 1, |
227 | | - } |
228 | | - ); |
229 | | - } else { |
230 | | - aniDuration = movingAniOptions.duration; |
231 | | - const offset = createAniOptions.duration / aniDuration; |
232 | | - framekeys.push( |
233 | | - { |
234 | | - transform: `translateY(${ |
235 | | - movingAniOptions.from + |
236 | | - (movingAniOptions.to - movingAniOptions.from) * offset |
237 | | - }px) scale(${createAniOptions.to})`, |
238 | | - offset: offset, |
239 | | - }, |
240 | | - { |
241 | | - transform: `translateY(${movingAniOptions.to}px)`, |
242 | | - offset: 1, |
243 | | - } |
244 | | - ); |
245 | | - } |
246 | | - node.contentNode.animate(framekeys, aniDuration); |
247 | | - } else if (movingAniOptions) { |
248 | | - node.contentNode.animate( |
249 | | - [ |
250 | | - { transform: `translateY(${movingAniOptions.from}px)` }, |
251 | | - { transform: `translateY(${movingAniOptions.to}px)` }, |
252 | | - ], |
253 | | - movingAniOptions.duration |
254 | | - ); |
255 | | - } else if (createAniOptions) { |
256 | | - node.contentNode.animate( |
257 | | - [ |
258 | | - { transform: `scale(${createAniOptions.from})` }, |
259 | | - { transform: `scale(${createAniOptions.to})` }, |
260 | | - ], |
261 | | - createAniOptions.duration |
262 | | - ); |
263 | | - } |
264 | | - if (l._dev) { |
265 | | - console.log(index, "do ani", stateEle.textContent); |
266 | | - console.log(movingAniOptions, createAniOptions); |
267 | | - for (const ani of node.contentNode.getAnimations()) { |
268 | | - console.log(ani.effect.getKeyframes()); |
269 | | - } |
270 | | - } |
271 | | - } |
272 | | - |
273 | | - node.contentNode.classList.toggle("first", index === 0n); |
274 | | - // node.contentNode.classList.toggle( |
275 | | - // "hide", |
276 | | - // node.contentNode.getAnimations().length === 0 && index === 2n |
277 | | - // ); |
278 | | - |
279 | | - // node.querySelector("[name=offsetTop]").innerHTML = node.offsetTop; |
280 | | - } else { |
281 | | - // console.log("%s %c%s", viewClass, "color:orange", type, index); |
282 | | - } |
283 | | - } |
284 | | - } |
285 | | - function gotoTop() { |
286 | | - l.virtualScrollTo(0); |
287 | | - } |
288 | | - function insertItem() { |
289 | | - l.itemCountStateManager.insertBefore(1n, 0n, { |
290 | | - // state: create |
291 | | - duration: movingDuration, |
292 | | - }); |
293 | | - } |
294 | | - function insertAndScroll() { |
295 | | - const count = (5 * Math.random()) | 0; |
296 | | - if (count > 0) { |
297 | | - l.itemCountStateManager.insertBefore(BigInt(count), 0n, { |
298 | | - state: "moving", |
299 | | - }); |
300 | | - } |
301 | | - let need_ani = l.virtualScrollTop <= l.itemSize * 2.5; |
302 | | - |
303 | | - /// 新区快在视野范围内,不进行滚动,让区块自然下落 |
304 | | - if (need_ani) { |
305 | | - l.itemCountStateManager.insertBefore(1n, 0n, { |
306 | | - duration: movingDuration, |
307 | | - }); |
308 | | - return; |
309 | | - } |
310 | | - /// 新区快在视野范围外,整个链保持静止不动,避免无意义的画面抖动 |
311 | | - else { |
312 | | - l.itemCountStateManager.insertBefore(1n, 0n, { |
313 | | - duration: 0, |
314 | | - }); |
315 | | - console.log(BigInt(l.itemSize * (count + 1)), count + 1); |
316 | | - l.virtualScrollTop += BigInt(l.itemSize * (count + 1)); |
317 | | - } |
318 | | - } |
319 | | - </script> |
| 147 | + <script type="module" src="main.ts"></script> |
320 | 148 | </html> |
0 commit comments