()
| 197 | |
| 198 | let cancelled = false; |
| 199 | const tryScroll = () => { |
| 200 | if (cancelled) return; |
| 201 | // 后退/前进还原阅读位置时(ScrollMemory 已接管),让位——否则会把页面又拽到 |
| 202 | // 锚点,盖掉用户离开时的真实滚动位置。所有滚动路径(路由变化 rAF、同页 |
| 203 | // hashchange)都汇到这里,故只在此判一次即可。同页脚注点击属「全新到达」、 |
| 204 | // ScrollMemory 不会 claim,不受影响。 |
| 205 | if (isScrollClaimed()) return; |
| 206 | const found = document.getElementById(hash); |
| 207 | if (!found) { |
| 208 | if (debug) console.warn("[HashScroller] element NOT found at scroll time", hash); |
| 209 | return; |
| 210 | } |
| 211 | // 表格锚点落在单元格上 → 归一到整张 <table>,否则会停在表格中部看不到表头 |
| 212 | const fresh = resolveBlockTarget(found); |
| 213 | const ancestor = findScrollableAncestor(fresh); |
| 214 | const elRect = fresh.getBoundingClientRect(); |
| 215 | if (debug) { |
| 216 | const isWin = ancestor instanceof Window; |
| 217 | console.log("[HashScroller] scrolling now", { |
| 218 | hash, |
| 219 | container: isWin ? "window" : "main", |
| 220 | containerScrollTop: isWin ? window.scrollY : (ancestor as HTMLElement).scrollTop, |
| 221 | containerScrollHeight: isWin |
| 222 | ? document.documentElement.scrollHeight |
| 223 | : (ancestor as HTMLElement).scrollHeight, |
| 224 | containerClientHeight: isWin |
| 225 | ? window.innerHeight |
| 226 | : (ancestor as HTMLElement).clientHeight, |
| 227 | elementTop: elRect.top, |
| 228 | elementText: fresh.textContent?.slice(0, 50), |
| 229 | }); |
| 230 | } |
| 231 | scrollElementToTop(fresh); |
| 232 | // 滚动以块起点为准(标题→标题本身),高亮则可跨多元素(标题 + 其下正文) |
| 233 | flashHighlight(resolveHighlightTargets(fresh)); |
| 234 | }; |
| 235 | |
| 236 | const onTimeout = () => { |
| 237 | if (debug) { |
nothing calls this directly
no test coverage detected