# 快速参考

> 版本速查、命名规范、代码模板

---

## 版本速查

### 当前版本
`0.0.2` → 下一目标 `0.0.3` ([M1.3](./M1.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": ["<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"
}
```

### 词典实现
```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 = `
      <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';
  }
}
```

### 通信封装
```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)
