docs: index 補齊增量恢復 API+data-jz-block-level 輸出鉤子(時效性同步至 8ee9895)

index.src.html 自 2026-07-11(738c917)後未同步,落後 main 四批變更。補齊兩處
消費端可見面,並刷新頁首時戳至 2026-07-17:

- 增量恢復 API(對應 main 2f04ea4/changelog c4f0ee0,Tier3):新增「動態頁面:
  增量恢復」一節——render/revert 傳局部 Element(O(該塊))、持久化 Finder、
  rerender/observe·disconnect(MutationObserver 自動增量)/invalidate,附元素
  變化之快取失效正確性注。
- data-jz-block-level 輸出鉤子(對應 main 8ee9895/建議七):新增專節——render
  時把 resolved 級別寫回直接承載文本之塊、純容器不標、輸入輸出分離、revert 全清;
  消費端 justify 白名單與段落級 pass 共用單一真相源。
- 增量塊粒度契約(說明八)與 revert 範圍注(不還原作者空格)以 callout 併入
  增量恢復節。
- md-source 孪生同步兩節。

build.sh 構建;headless Chrome 渲染核對——兩節入 runtime TOC(toc-5/toc-9)、
無報錯。
This commit is contained in:
2026-07-17 19:35:37 +08:00
parent 1a5f0078c6
commit 45f67668fe
2 changed files with 755 additions and 178 deletions
+701 -176
View File
File diff suppressed because it is too large Load Diff
+54 -2
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>聚珍(Juzhen</title> <title>聚珍(Juzhen</title>
<meta name="generated-at" content="2026-06-02"> <meta name="generated-at" content="2026-07-17">
<meta name="source" content="cjk-autospace · 使用文檔"> <meta name="source" content="cjk-autospace · 使用文檔">
<!-- RUNTIME_CSS --> <!-- RUNTIME_CSS -->
</head> </head>
@@ -14,7 +14,7 @@
<div class="meta"> <div class="meta">
<h1>聚珍(Juzhen</h1> <h1>聚珍(Juzhen</h1>
<p class="subtitle">現代簡/繁中文網頁排版套件——Han.css 之現代化重寫,複製乾淨、依 lang 全角/開明切換、justify 句末標點單份間距、跨瀏覽器一致。</p> <p class="subtitle">現代簡/繁中文網頁排版套件——Han.css 之現代化重寫,複製乾淨、依 lang 全角/開明切換、justify 句末標點單份間距、跨瀏覽器一致。</p>
<p class="timestamp"><time>2026-06-02</time> · <span>cjk-autospace · 使用文檔</span></p> <p class="timestamp"><time>2026-07-17</time> · <span>cjk-autospace · 使用文檔</span></p>
</div> </div>
<div class="actions"> <div class="actions">
<!-- ACTIONS --> <!-- ACTIONS -->
@@ -49,6 +49,27 @@ import "cjk-autospace/css";
createJuzhen({ lang: { default: "zh-Hant" } }).render(document.querySelector("main"));</code></pre> createJuzhen({ lang: { default: "zh-Hant" } }).render(document.querySelector("main"));</code></pre>
<div class="callout info"><span class="label">JS 與 CSS 缺一不可</span> JS 只注入 <code>jz-*</code> 結構,所有視覺尺寸(間隙寬度、擠壓量、<code>justify</code> 原子化、字體堆疊)都在 <code>juzhen.css</code>。缺 CSS 則全部失效。</div> <div class="callout info"><span class="label">JS 與 CSS 缺一不可</span> JS 只注入 <code>jz-*</code> 結構,所有視覺尺寸(間隙寬度、擠壓量、<code>justify</code> 原子化、字體堆疊)都在 <code>juzhen.css</code>。缺 CSS 則全部失效。</div>
<h3>動態頁面:增量恢復(局部變化免全樹重掃)</h3>
<p><code>render(root)</code><code>revert(root)</code> <strong>皆可傳入局部 Element</strong>——頁面局部變化時只重處理受影響之子樹,成本 <code>O(該塊)</code> 而非 <code>O(全文)</code>(實測編輯 400 段中之一段,局部恢復較全樹重掃快數百倍)。實例內部持久化 <code>Finder</code>,跨 <code>render</code> 復用元素分類/功能級別/功能開關之快取,非每次重建。</p>
<pre><code>const jz = createJuzhen();
jz.render(document.body); // 初次全樹
// 局部變化後(手動):
jz.rerender(changedBlock); // revert(changedBlock) + render(changedBlock)
jz.render(newlyAppendedBlock); // 新增之塊:直接 render(無須 revert
// 自動(opt-in):觀察 DOM,內容/分類屬性變化時只重處理受影響之最近塊
jz.observe(document.body);
// jz.disconnect(); // 停止觀察</code></pre>
<ul>
<li><strong><code>rerender(root?)</code></strong><code>revert</code><code>render</code> 同一(子)樹之便利方法。</li>
<li><strong><code>observe(root?)</code><code>disconnect()</code></strong>:以 <code>MutationObserver</code> 自動增量。聚珍自身之注入於處理期間暫停觀察、<strong>絕不自觸發</strong>;新增之塊直接 render(免全容器重掃)。需 <code>MutationObserver</code>(瀏覽器/jsdom 有,無則 no-op)。</li>
<li><strong><code>invalidate(root?)</code></strong>:清該子樹之內部快取。<code>revert</code> 已自動失效其子樹,故僅在「改了既有元素之分類相關屬性(<code>class</code><code>data-jz-*</code><code>lang</code><strong>但不走 <code>revert</code></strong>」時才需顯式調用。純內容(子節點/文本)變化不改分類、無需 <code>invalidate</code>(但仍須 <code>revert</code><code>render</code> 該塊方能重處理)。</li>
</ul>
<div class="callout info"><span class="label">元素變化之正確性</span> 快取隨實例持久、非每次 render 重建。<strong>改變既有元素之分類相關屬性(分類/級別/功能開關)後,須經 <code>revert</code><code>rerender</code><code>invalidate</code><code>observe</code> 任一使該子樹快取失效</strong>,否則沿用舊分類。新增/移除元素與純內容編輯無此顧慮(新元素重算、移除者自動回收)。</div>
<div class="callout"><span class="label">增量之粒度為「塊」</span> 換塊內容(<code>textContent</code><code>innerHTML</code>)、增刪塊、改分類屬性——皆與全量重繪一致。<strong>不支持</strong>對聚珍已切分之文本節點做外科式 <code>characterData</code> 直改(如持有 render <strong></strong><code>p.firstChild</code> 引用、事後直改其 <code>.data</code>):render 後原文本節點已被 <code>jz-*</code> 切分/替換,該引用已非原整段。此為後處理排版器之固有限制(任何外科式文本 patch 之框架皆會與注入後之 DOM 失步)、<strong>非缺陷</strong>——聚珍對當前 DOM 之處理始終自洽。欲改文字,以塊為單位替換內容即可。</div>
<div class="callout warn"><span class="label">revert 之範圍</span> <code>revert</code> 乾淨移除聚珍注入之全部結構(<code>jz-*</code><code>data-jz-*</code>),DOM 回到<strong>邏輯等價</strong>態;但<strong>不還原</strong> <code>spacing</code> 依契約規範化之贅餘作者空格(CJK↔西文吸收為間隙、CJK↔CJK 剝除)。差異穩定、不隨反覆 render/revert 累積。消費端若需保留原始作者空格以供編輯,應自存原文、<strong>勿以 <code>revert</code> 當「還原到未處理源碼」</strong></div>
<h2>已實作功能</h2> <h2>已實作功能</h2>
<table> <table>
<thead><tr><th>功能</th><th>說明</th></tr></thead> <thead><tr><th>功能</th><th>說明</th></tr></thead>
@@ -90,6 +111,22 @@ createJuzhen({ lang: { default: "zh-Hant" } }).render(document.querySelector("ma
&lt;p data-juzhen-off="jiya"&gt;&lt;/p&gt; &lt;!-- 黑名單:停用 jiya,其餘繼承 --&gt; &lt;p data-juzhen-off="jiya"&gt;&lt;/p&gt; &lt;!-- 黑名單:停用 jiya,其餘繼承 --&gt;
&lt;div lang="zh-Hans"&gt;&lt;/div&gt; &lt;!-- lang 驅動全角/開明 --&gt;</code></pre> &lt;div lang="zh-Hans"&gt;&lt;/div&gt; &lt;!-- lang 驅動全角/開明 --&gt;</code></pre>
<h2><code>data-jz-block-level</code>resolved 分類之 CSS 鉤子(輸出屬性)</h2>
<p><code>render</code> 時,聚珍把 <strong>resolved</strong> 功能級別寫回每個「直接承載可處理文本」之塊級元素,供消費端 CSS 查詢——與段落級功能(見上「功能分級」)之判定同源:</p>
<pre><code>&lt;div class="callout" data-jz-block-level="paragraph"&gt;&lt;/div&gt; &lt;!-- 判為段落級 --&gt;
&lt;h2 data-jz-block-level="text"&gt;&lt;/h2&gt; &lt;!-- 判為文本級 --&gt;
&lt;ul&gt; &lt;!-- 純容器:不標 --&gt;
&lt;li data-jz-block-level="paragraph"&gt;&lt;/li&gt;
&lt;/ul&gt;</code></pre>
<p>消費端之<strong>段落級 CSS</strong>(首要:CJK 兩端對齊)從此與聚珍之段落級 pass(禁則/垂懸)共用<strong>單一真相源</strong>,免另行維護一份必然漂移之選擇器白名單:</p>
<pre><code>[data-jz-block-level="paragraph"] { text-align: justify; }
.marginalia[data-jz-block-level="paragraph"] { text-align: start; } /* 窄欄 opt-out */</code></pre>
<ul>
<li><strong>僅標直接承載文本之塊</strong>——純容器(<code>body</code><code>ul</code><code>table</code>…,直接文本僅空白)不標,否則 <code>body</code> 恆被判段落級、justify 鉤子經繼承污染全頁。此集合恰為段落級 pass 實際作用之塊集;avoid 子樹/pill 內部之文本不計,故未被處理之塊一致不標。</li>
<li><strong>輸出專用、輸入輸出分離</strong>:作者輸入屬性 <code>data-jz-level</code> 只讀不寫;本屬性由聚珍寫入、<strong>絕不讀取</strong>(消費端手寫無效),<code>revert</code> 時全數移除。增量模式(<code>observe</code>)下分類屬性變化自動刷新。</li>
<li>是否對齊仍由消費端 CSS 決定(justify 非段落之純函數——窄欄邊注可 opt-out);聚珍只供分類、<strong>不介入樣式</strong></li>
</ul>
<h2>標點半形:<code>halt</code> 預設與 <code>margin</code> 後備</h2> <h2>標點半形:<code>halt</code> 預設與 <code>margin</code> 後備</h2>
<p>開明/半角式把標點收成「半形」,有兩種渲染機制:</p> <p>開明/半角式把標點收成「半形」,有兩種渲染機制:</p>
<table> <table>
@@ -216,6 +253,17 @@ createJuzhen({ lang: { default: "zh-Hant" } }).render(document.querySelector("ma
JS 只注入 `jz-*` 結構,所有視覺尺寸在 juzhen.css,缺一不可。 JS 只注入 `jz-*` 結構,所有視覺尺寸在 juzhen.css,缺一不可。
## 動態頁面:增量恢復(局部變化免全樹重掃)
`render(root)``revert(root)` 皆可傳入局部 Element,成本 O(該塊) 而非 O(全文)(實測編輯 400 段中之一段快數百倍)。實例持久化 Finder,跨 render 復用元素分類/級別/開關快取、非每次重建。
- `rerender(root?)`revert 後 render 同一子樹之便利方法。
- `observe(root?)``disconnect()`:以 MutationObserver 自動增量;聚珍注入期間暫停觀察、絕不自觸發;新增之塊直接 render。需 MutationObserver(瀏覽器/jsdom 有,無則 no-op)。
- `invalidate(root?)`:清子樹快取;revert 已自動失效,僅「改既有元素之 class/data-jz-*lang 等分類屬性但不走 revert」時需顯式調用。純內容變化不改分類。
- 元素變化正確性:快取隨實例持久;改既有元素之分類相關屬性後須經 revertrerenderinvalidateobserve 任一失效該子樹,否則沿用舊分類。新增/移除與純內容編輯無此顧慮。
- 增量之粒度為「塊」:換塊內容(textContent/innerHTML)、增刪塊、改分類屬性皆與全量一致;不支持對已切分文本節點之外科式 characterData 直改(render 後原節點已被 jz-* 替換,舊引用已脫離)——後處理排版器之固有限制、非缺陷。欲改文字以塊為單位替換內容即可。
- revert 之範圍:乾淨移除 jz-*data-jz-*DOM 回邏輯等價態;但不還原 spacing 契約規範化之作者空格(CJK↔西文吸收、CJK↔CJK 剝除),差異穩定不累積。需原始源請自存、勿以 revert 當還原源碼。
## 已實作功能 ## 已實作功能
- spacing 中西間隙(margin 模型,copy-clean;含 pill/隔離元素邊界與作者空格正規化)【文本級】 - spacing 中西間隙(margin 模型,copy-clean;含 pill/隔離元素邊界與作者空格正規化)【文本級】
@@ -227,6 +275,10 @@ JS 只注入 `jz-*` 結構,所有視覺尺寸在 juzhen.css,缺一不可。
- level 功能分級(文本級 vs 段落級;data-jz-level="text"level:{text:選擇器} 標記標題等僅跑文本級) - level 功能分級(文本級 vs 段落級;data-jz-level="text"level:{text:選擇器} 標記標題等僅跑文本級)
- justify 句末標點單份間距(jz-char inline-block 原子) - justify 句末標點單份間距(jz-char inline-block 原子)
## data-jz-block-levelresolved 分類之 CSS 鉤子(輸出屬性)
render 時把 resolved 功能級別寫回每個「直接承載可處理文本」之塊:`data-jz-block-level="paragraph|text"`。純容器(bodyul/table,直接文本僅空白)不標,否則 body 恆判段落級、justify 經繼承污染全頁;此集合恰為段落級 pass 作用之塊集,avoid 子樹/pill 內部之文本不計。消費端段落級 CSS 從此與禁則/垂懸共用單一真相源:`[data-jz-block-level="paragraph"]{ text-align: justify }``.marginalia[data-jz-block-level="paragraph"]{ text-align: start }`(窄欄 opt-out)。輸出專用、輸入輸出分離:作者輸入 data-jz-level 只讀不寫,本屬性聚珍絕不讀取(手寫無效)、revert 全移除、observe 下自動刷新。是否對齊由消費端 CSS 決定,聚珍只供分類、不介入樣式。
## 標點半形:halt 預設與 margin 後備 ## 標點半形:halt 預設與 margin 後備
- halt(預設,`jiya: true`):字型 OpenType halt 定位,需字型支援。 - halt(預設,`jiya: true`):字型 OpenType halt 定位,需字型支援。