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