bp-tools-patch.js
六個元件,一個補丁
只需兩個 script 標籤,為任何網頁加入 InfoRegion、DualCell、WordFlip、bp-slide、bp-notice、BpNote 六大元件,並透過 BPTools 事件匯流排串接所有互動。
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<!-- 2. 主工具庫(永遠不動)-->
<script src="bp-tools.js"></script>
<!-- 3. 擴充補丁(所有新功能)-->
<script src="bp-tools-patch.js"></script>
快速開始
頁面裡使用 BPTools 訂閱事件時,必須用輪詢寫法,確保 BPTools 建立完成後才執行。
// ✓ 正確:輪詢等待 (function wait() { if (typeof BPTools === 'undefined') { setTimeout(wait, 50); return; } BPTools.on('my:event', () => { /* 你的邏輯 */ }); })(); // ✗ 錯誤:DOMContentLoaded 不保證 BPTools 已就緒 document.addEventListener('DOMContentLoaded', () => { BPTools.on('my:event', ...); // 可能噴 BPTools is not defined });
window.StickyNotesConfig 覆蓋預設值。各元件的設定方式詳見各自章節。BPTools 事件匯流排
六個元件的通訊中樞。發布端不知道誰在聽,訂閱端不知道誰觸發,靠事件名稱字串鬆散耦合。_fired 紀錄歷史,後來載入的元件也能知道事件是否已發過並立即解鎖。
訂閱事件。同一事件可訂閱多次,全部觸發。
發布事件。同時記入 _fired 歷史。
取消特定訂閱。
Set<string>,記錄所有曾發過的事件名稱。
BPTools.on('lesson:done', () => badge.style.display = 'block'); BPTools.on('lesson:done', () => fetch('/api/progress', { method: 'POST' })); BPTools.on('lesson:done', () => localStorage.setItem('done', '1'));
主體:動作 格式,例如 quiz:pass、lesson:done、slide:revealed。描述「發生了什麼」而不是「要做什麼」。品牌色系
所有元件共用同一套色系,透過 BrandColors 統一管理。支援深色/淺色雙主題切換。
BrandColors.applyTheme('light'); // 切換主題,全頁自動更新 BrandColors.get('sky'); // '#04b5a3' BrandColors.get('sky', 'light'); // '#027a6c'(淺色主題值) BrandColors.resolve('sky'); // 同 get,找不到時原值回傳
InfoRegion 步驟引導
逐步動畫顯示的說明區塊,支援自動播放、倒數、手動確認、全域進度條。patch 新增分支路徑與 link 事件發布。
<info-region-group global-progress progress-color="sky" show-percent start-label="▶ 開始" start-color="sky"> <info-region id="s1" color="sky" next="s2" countdown="2000"> 第一步,2 秒後自動前進。 </info-region> <info-region id="s2" color="lavender" manual manual-label="下一步 →" link="lesson:done"> 第二步,手動確認,完成時發出 lesson:done 事件。 </info-region> </info-region-group>
<info-region id="q1" color="lavender" choice-align="left"> <p>問題文字</p> <ir-choice target="ans-ok" color="safe" icon="check-circle">正確選項</ir-choice> <ir-choice target="ans-no" color="warning" icon="x-circle">錯誤選項</ir-choice> </info-region> <!-- 答錯:next 指回題目,自動重置 --> <info-region id="ans-no" color="warning" next="q1"> ✗ 不對,再試一次。 </info-region>
patch 新增屬性
| 屬性(info-region) | 預設 | 說明 |
|---|---|---|
| link | — | 啟動時向匯流排發出事件 |
| 屬性(ir-choice) | ||
| target | 必填 | 點擊後跳往的 info-region id |
| color | 父層色 | 按鈕品牌色 |
| icon | — | Bootstrap Icon 類名(不含 bi-) |
| 屬性(info-region,choice-align) | ||
| choice-align | left | 選項按鈕對齊:left / center / right |
DualCell 多欄表格
語義化多欄表格,支援主題色、遮罩揭示、群組折疊、輪播等。patch 新增 on-link,訂閱事件後自動移除遮罩。
<div id="t1" data-dual-cell data-cols="2" data-theme="sky" data-show-menu-button="false"> <div data-col>問題</div> <!-- on-link:監聽事件,事件發生後移除遮罩 --> <div data-col data-on-link="quiz:pass" data-overlay-1-text="答對後解鎖"> 答案內容 </div> </div>
patch 新增屬性
| 屬性(data-col) | 說明 |
|---|---|
| data-on-link | 事件名稱。事件發生時移除此格的所有遮罩,取消 blur。 |
WordFlip 行內互動詞彙
夾在段落中的可點擊詞彙,點擊後展開說明。patch 新增四項擴充,並支援 12 種視覺樣式。
<!-- link:翻開時發出事件 --> <word-flip data-color="sky" link="term:opened" data-content="說明文字">詞彙</word-flip> <!-- unlock-on:預設鎖定,事件發生後才可點擊 --> <word-flip data-color="safe" unlock-on="quiz:pass" data-content="解鎖後的說明">鎖定中</word-flip> <!-- answer-src:從外部元素讀取 HTML 內容 --> <div id="my-detail" style="display:none"><strong>完整 HTML 說明</strong></div> <word-flip data-color="lavender" answer-src="my-detail">詞彙</word-flip> <!-- group:同組互斥,同時只展開一個 --> <word-flip data-color="sky" group="terms" data-content="A 的說明">詞 A</word-flip> <word-flip data-color="lavender" group="terms" data-content="B 的說明">詞 B</word-flip>
全部 style-type 樣式
★ = patch 新增樣式
data-content,不是 answer。ir-challenge 輸入驗證
答對才向匯流排發出事件,可連動解鎖任意訂閱同一事件的元件。支援多個正確答案。
<ir-challenge answer="Cookie|cookie|COOKIE" <!-- | 分隔多個答案 --> link="q:correct" <!-- 答對後發出的事件 --> color="sky" placeholder="輸入答案…" hint="提示文字" btn-label="確認" font-size="1rem" <!-- 同時設定輸入框與按鈕 --> btn-font-size="0.9rem" <!-- 單獨設定按鈕 --> input-font-size="1rem" <!-- 單獨設定輸入框 --> btn-padding="8px 24px" case-sensitive> <!-- 加上此屬性則區分大小寫 --> </ir-challenge>
| 屬性 | 預設 | 說明 |
|---|---|---|
| answer | 必填 | 正確答案,| 分隔多個 |
| link | — | 答對後向匯流排發出的事件名稱 |
| color | sky | 品牌色(影響邊框、按鈕、focus 光暈) |
| placeholder | 輸入答案… | 輸入框提示 |
| hint | — | 輸入框下方灰色提示文字 |
| btn-label | 確認 | 按鈕文字 |
| font-size | — | 同時設定輸入框與按鈕字體 |
| input-font-size | — | 單獨設定輸入框字體 |
| btn-font-size | — | 單獨設定按鈕字體 |
| btn-padding | 7px 20px | 按鈕 padding |
| case-sensitive | — | 布林屬性,加上後區分大小寫 |
bp-slide 投影片
原 slider-show.js 已整合進 patch,標籤改為 <bp-slide>。完整保留原有功能,新增四個匯流排連動屬性。
<bp-slide theme="orange" height="240px" link="slider:done" <!-- 按完成按鈕時發事件 --> unlock-on="quiz:pass" <!-- 等事件才解鎖整個導航 --> auto-show-part-buttons="true" finish-btn-text="完成課程 →"> <div slide part="1">第一頁</div> <!-- 切換到此頁時發出事件 --> <div slide part="1" link="slide:p2">第二頁</div> <!-- 停在此頁時鎖住下一頁,等 quiz:pass 才放行 --> <div slide part="1" unlock-on="quiz:pass">第三頁</div> </bp-slide>
patch 新增連動屬性
| 屬性位置 | 屬性 | 說明 |
|---|---|---|
| <bp-slide> | link | 按「完成」按鈕時發出事件 |
| <bp-slide> | unlock-on | 等事件才解鎖整個 slider 的導航 |
| [slide] | link | 切換到此張時發出事件 |
| [slide] | unlock-on | 停在此張時鎖住下一頁,等事件才放行 |
bp-notice 公告元件
區塊級公告,支援燃燒引線倒數動畫、可關閉、置頂固定、事件解鎖。內文支援完整 HTML 與 Bootstrap Icons。
<!-- 燃燒引線 + 可關閉 --> <bp-notice color="sky" icon="info-circle-fill" <!-- Bootstrap Icon 類名 --> font-size="1rem" icon-size="1.4rem" padding="16px 20px" dismissible <!-- 顯示關閉按鈕 --> auto-hide="5000" <!-- 5 秒後燃盡消失 --> sticky <!-- 置頂固定 --> unlock-on="lesson:done" <!-- 等事件才顯示,顯示後才倒數 --> link="notice:closed" <!-- 關閉時發出事件 -->> <!-- 完整 HTML + Bootstrap Icons --> <strong>公告標題</strong> <ul> <li><i class="bi bi-check2"></i> 項目一</li> </ul> </bp-notice>
| 屬性 | 預設 | 說明 |
|---|---|---|
| color | sky | 品牌色 |
| icon | — | 左側 Bootstrap Icon 類名(不含 bi-) |
| font-size | .92rem | 整體字體大小 |
| icon-size | 1.2rem | 左側圖示大小 |
| padding | 14px 18px | 內距 |
| dismissible | — | 布林屬性,顯示關閉按鈕 |
| auto-hide | — | 毫秒數,到時燃燒引線燃盡後淡出 |
| sticky | — | 布林屬性,position:sticky 置頂 |
| unlock-on | — | 等匯流排事件才顯示,顯示後才開始倒數 |
| link | — | 關閉或 auto-hide 消失時發出的事件 |
auto-hide 屬性後底部自動出現引線動畫,火花顏色跟隨 color 屬性,無需額外設定。BpNote 便利貼
雙擊頁面任意空白處建立便利貼。整合 BrandColors 品牌色,支援拖曳、調色、收合、localStorage 自動儲存,並可透過 BPTools 匯流排通知其他元件。
<script> window.StickyNotesConfig = { defaultColor : 'lavender', // 品牌色名稱或 hex defaultWidth : 280, position : 'fixed', // 'fixed' | 'absolute' storageKey : 'my_notes', // localStorage 鍵名 excludeClass : 'no-sticky', // 掛此 class 的元素不觸發 fontSize : '1rem', // 便利貼字體大小 lineHeight : '1.8', // 便利貼行高 link : 'note:saved', // 操作時向匯流排發出的事件 }; </script>
手動觸發 localStorage 儲存。
清除所有便利貼。
回傳 JSON 陣列,可存入資料庫。
批次匯入便利貼資料(疊加)。
暫停雙擊建立功能。
恢復雙擊建立功能。
window.StickyWall 是 BpNote 的別名,原本使用 sticky-wall.js 的程式碼無需修改。// 存入資料庫 const data = BpNote.export(); fetch('/api/save-notes', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); // 從資料庫還原 fetch('/api/load-notes') .then(r => r.json()) .then(arr => BpNote.import(arr));
連動流程範例
以雅思口說教學場景為例,展示五個元件如何透過一個事件名稱串接完整的學習流程。
<!-- 投影片:答題通過才進第三頁,完成發事件 --> <bp-slide theme="orange" link="slider:done" auto-show-part-buttons="true"> <div slide part="1" link="slide:intro">第一頁</div> <div slide part="1" unlock-on="quiz:pass">第二頁(鎖住)</div> </bp-slide> <!-- 答題:答對後解鎖所有訂閱 quiz:pass 的元件 --> <ir-challenge answer="Cookie" link="quiz:pass" color="lavender"></ir-challenge> <!-- 答案表格:答對解鎖 --> <div data-dual-cell data-cols="2" data-theme="lavender"> <div data-col>問題</div> <div data-col data-on-link="quiz:pass" data-overlay-1-text="答對後解鎖">答案</div> </div> <!-- 完課公告:完成投影片才顯示,5 秒引線 --> <bp-notice color="special" icon="stars" unlock-on="slider:done" auto-hide="5000" dismissible> 🎓 課程完成! </bp-notice>
所有公開 API
patch 載入後全域可用的所有物件與方法。
/* BPTools 匯流排 */ BPTools.on(ev, fn) // 訂閱 BPTools.emit(ev, data) // 發布 BPTools.off(ev, fn) // 取消訂閱 BPTools._fired // Set,已發過的事件歷史 /* BrandColors */ BrandColors.applyTheme('dark' | 'light') BrandColors.get(colorName) BrandColors.resolve(val) BrandColors.toCSSVars(themeName) /* InfoRegion */ InfoRegion.activate(id) InfoRegion.resetAll() /* BpNote(便利貼)*/ BpNote.save() BpNote.clearAll() BpNote.export() // → JSON 陣列 BpNote.import(arr) BpNote.enable() / disable() StickyWall // BpNote 的別名(向後相容)
相容性與注意事項
| 項目 | 說明 |
|---|---|
| 瀏覽器支援 | Chrome 80+、Edge 80+、Firefox 75+、Safari 14+。使用 Custom Elements v1、CSS 變數、ResizeObserver。 |
| 相依檔案 | bp-tools.js 必須在 patch 之前載入。Bootstrap Icons CSS 為選填,但 icon 屬性需要它。 |
| slider-show.js | 已整合進 patch,可以移除。<slider-show> 舊標籤須改為 <bp-slide>。 |
| sticky-wall.js | 已整合進 patch,可以移除。StickyWall 別名保留,舊程式碼不需修改。 |
| word-flip 屬性 | 展開內容用 data-content,不是 answer。patch 的 answer-src 功能不受影響。 |
| BPTools 訂閱時機 | 頁面 script 裡使用 BPTools 須用輪詢寫法,避免 BPTools is not defined 錯誤。 |
| unlock-on + auto-hide | bp-notice 的倒數從「公告出現後」才開始,不是頁面載入時。 |