fix: HTML 预览锚点点击同步 hash,修复多页面技能子页面切换失效

预览 iframe 注入的锚点拦截脚本只 preventDefault + scrollIntoView,
URL hash 从未改变,html-multipage 技能基于 CSS :target 的子页面
切换永远不命中,子页面 section 保持隐藏,点击无效。改为拦截后
同步 location.hash 触发 :target 切页,仅当目标元素已渲染时再平滑滚动。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
吉鑫升andClaude Fable 5 committed 2026-06-12 21:49:32 +08:00
1 parent 74113b3e6e
commit 21e53310f8
1 file changed
+16 -5
+16 -5
View File
@@ -100,9 +100,16 @@ function candidateTextFromHref(href: string): string {
/**
* Injects a small runtime script into generated HTML so that clicking an
* in-page anchor (`<a href="#section">`) scrolls within the iframe instead of
* navigating it. The preview iframe loads from a sandboxed `blob:` URL, where a
* fragment navigation blanks the frame; intercepting the click avoids that.
* in-page anchor (`<a href="#section">`) works inside the preview iframe.
*
* The hash MUST really change on click: multi-page documents (the
* html-multipage skill) show/hide their sub-page `<section class="page">`
* blocks with CSS `:target` rules, which only fire on a fragment navigation.
* Intercepting with preventDefault + scrollIntoView alone leaves the hash
* untouched, so sub-pages stay `display:none` and clicks look dead. The
* handler therefore syncs `location.hash` (a same-document navigation —
* safe in the sandboxed blob: frame) and only smooth-scrolls afterwards when
* the target is actually rendered.
*/
export function injectInPageAnchorHandler(html: string): string {
const script = `<script>(function(){
@@ -119,8 +126,8 @@ export function injectInPageAnchorHandler(html: string): string {
var href=el.getAttribute("href");
if(!href||href.charAt(0)!=="#"||href.length<2)return;
e.preventDefault();
var id=decode(href.slice(1));
var raw=href.slice(1);
var id=decode(raw);
var target=
document.getElementById(id)||
document.getElementById(raw)||
@@ -128,7 +135,11 @@ export function injectInPageAnchorHandler(html: string): string {
document.getElementsByName(raw)[0]||
bySelector(id)||
bySelector(raw);
if(target){target.scrollIntoView({behavior:"smooth",block:"start"});}
try{if(location.hash!=="#"+raw){location.hash=raw;}}catch(err){}
if(!target)return;
requestAnimationFrame(function(){
if(target.getClientRects().length){target.scrollIntoView({behavior:"smooth",block:"start"});}
});
},true);
})();</script>`;
if (/<\/body>/i.test(html)) {