4.8 KiB
4.8 KiB
快速参考
版本速查、命名规范、代码模板
版本速查
当前版本
0.1.7 → 下一目标 0.1.8 (M2.8)
模块版本范围
| 模块 | 范围 | 任务数 |
|---|---|---|
| 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 |
版本更新
# 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 |
消息类型速查
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)
{
"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)
{
"manifest_version": 3,
"name": "沙拉查词",
"version": "0.0.0",
"permissions": ["storage", "contextMenus", "clipboardWrite"],
"optional_permissions": ["clipboardRead"],
"host_permissions": ["<all_urls>"],
"background": {
"service_worker": "src/background/index.js",
"type": "module"
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["src/content/index.js"],
"run_at": "document_end"
}],
"action": {
"default_popup": "src/popup/index.html"
},
"options_page": "src/options/index.html"
}
词典实现
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组件
export class XxxComponent extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({ mode: 'open' });
this.render();
}
render() {
this.shadow.innerHTML = `
<style>
:host { display: block; position: fixed; }
.container { background: var(--salad-bg, #fff); }
</style>
<div class="container">...</div>
`;
}
show(x, y) {
this.style.left = `${x}px`;
this.style.top = `${y}px`;
this.style.display = 'block';
}
hide() {
this.style.display = 'none';
}
}
通信封装
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();
调试技巧
// 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)