# 快速参考 > 版本速查、命名规范、代码模板 --- ## 版本速查 ### 当前版本 `0.1.6` → 下一目标 `0.1.7` ([M2.7](./M2.md)) ### 模块版本范围 | 模块 | 范围 | 任务数 | |------|------|--------| | M1 | 0.0.1 ~ 0.0.5 | 5 | | M2 | 0.1.1 ~ 0.1.9 | 9 | | M3 | 0.2.1 ~ 0.2.11 | 11 | | M4 | 0.3.1 ~ 0.3.8 | 8 | | M5 | 0.4.1 ~ 0.4.16 | 16 | | M6 | 0.5.1 ~ 0.5.7 | 7 | | M7 | 0.6.1 ~ 0.6.6 | 6 | | M8 | 0.7.1 ~ 0.7.10 | 10 | | M9 | 0.8.1 ~ 0.8.7 | 7 | | M10 | 0.9.1 ~ 0.9.8 | 8 | | M11 | 0.10.1 ~ 1.0.0 | 10 | ### 版本更新 ```bash # M1.1 完成后 版本: 0.0.0 → 0.0.1 git commit -m "feat(M1.1): 项目初始化 (v0.0.1)" # M2.1 完成后 (进入M2) 版本: 0.0.5 → 0.1.1 git commit -m "feat(M2.1): 文本选择检测 (v0.1.1)" ``` --- ## 命名速查 | 类型 | 规范 | 示例 | |------|------|------| | 文件 | 小写+连字符 | `salad-icon.js` | | 类 | PascalCase | `DictionaryBase` | | 函数 | camelCase+动词 | `getSelectionCoords()` | | 常量 | UPPER_SNAKE | `DEFAULT_TIMEOUT` | | 私有 | _前缀 | `_cache`, `_handle()` | | 消息 | 大写+点 | `DICT.SEARCH` | --- ## 消息类型速查 ```javascript DICT.SEARCH / DICT.SEARCH_RESPONSE CONFIG.GET / CONFIG.SET / CONFIG.CHANGED WORD.ADD_FAVORITE / WORD.REMOVE_FAVORITE CLIPBOARD.READ / CLIPBOARD.WRITE HTTP.GET / HTTP.POST ``` --- ## 代码模板 ### package.json(0.0.0) ```json { "name": "salad-dict", "version": "0.0.0", "type": "module", "scripts": { "dev": "vite", "build": "vite build" }, "dependencies": { "vue": "^3.4.0", "vue-router": "^4.2.0", "pinia": "^2.1.0", "localforage": "^1.10.0" }, "devDependencies": { "@crxjs/vite-plugin": "^2.0.0", "@vitejs/plugin-vue": "^5.0.0", "vite": "^5.0.0" } } ``` ### manifest.json(0.0.0) ```json { "manifest_version": 3, "name": "沙拉查词", "version": "0.0.0", "permissions": ["storage", "contextMenus", "clipboardWrite"], "optional_permissions": ["clipboardRead"], "host_permissions": [""], "background": { "service_worker": "src/background/index.js", "type": "module" }, "content_scripts": [{ "matches": [""], "js": ["src/content/index.js"], "run_at": "document_end" }], "action": { "default_popup": "src/popup/index.html" }, "options_page": "src/options/index.html" } ``` ### 词典实现 ```javascript import { DictionaryBase } from './base.js'; import { messaging } from '../messaging.js'; export class XxxDictionary extends DictionaryBase { constructor(config = {}) { super({ name: '词典名', icon: 'icon.png', languages: ['en', 'zh'], ...config }); } async search(word) { if (!word?.trim()) throw new Error('Word is empty'); const html = await messaging.send('HTTP.GET', { url: `...${encodeURIComponent(word)}` }); return this.parse(html, word); } parse(html, word) { const doc = new DOMParser().parseFromString(html, 'text/html'); return { word, phonetic: '', meanings: [{ partOfSpeech: 'n.', definitions: ['释义'] }], examples: [{ sentence: '例句', translation: '翻译' }], url: '' }; } } ``` ### UI组件 ```javascript export class XxxComponent extends HTMLElement { constructor() { super(); this.shadow = this.attachShadow({ mode: 'open' }); this.render(); } render() { this.shadow.innerHTML = `
...
`; } show(x, y) { this.style.left = `${x}px`; this.style.top = `${y}px`; this.style.display = 'block'; } hide() { this.style.display = 'none'; } } ``` ### 通信封装 ```javascript class MessageClient { async send(type, payload, timeout = 5000) { const requestId = generateUUID(); return new Promise((resolve, reject) => { const timer = setTimeout(() => reject(new Error('Timeout')), timeout); const handler = (response) => { if (response.meta?.requestId !== requestId) return; clearTimeout(timer); chrome.runtime.onMessage.removeListener(handler); response.error ? reject(new Error(response.error.message)) : resolve(response.payload); }; chrome.runtime.onMessage.addListener(handler); chrome.runtime.sendMessage({ type, payload, meta: { requestId } }); }); } } export const messaging = new MessageClient(); ``` --- ## 调试技巧 ```javascript // Content Script console.log('[Content]', message); // Background (看 Service Worker console) chrome.action.onClicked.addListener(() => { console.log('[Background]', 'clicked'); }); // 强制刷新扩展 chrome.runtime.reload(); ``` **Chrome 扩展 DevTools**: - `chrome://extensions/` → "service worker" (background) - "inspect views" (popup)