update at 2025-10-08 19:45:28
This commit is contained in:
461
ARCHITECTURE_QUICK_REFERENCE.md
Normal file
461
ARCHITECTURE_QUICK_REFERENCE.md
Normal file
@@ -0,0 +1,461 @@
|
||||
# 新架构快速参考指南
|
||||
|
||||
## 📋 文件结构
|
||||
|
||||
```
|
||||
src/
|
||||
├── preview-view.ts # Obsidian 视图容器 (241 行)
|
||||
├── preview-manager.ts # 中央调度器 (368 行) ★
|
||||
├── platform-chooser.ts # 平台选择器 (172 行)
|
||||
├── wechat/
|
||||
│ └── wechat-preview.ts # 微信预览 (274 行)
|
||||
└── xiaohongshu/
|
||||
└── xhs-preview.ts # 小红书预览 (390 行)
|
||||
```
|
||||
|
||||
## 🎯 各文件职责
|
||||
|
||||
### preview-view.ts
|
||||
**角色**:Obsidian 视图容器
|
||||
**职责**:
|
||||
- 实现 `ItemView` 接口
|
||||
- 管理视图生命周期
|
||||
- 监听 Obsidian 事件
|
||||
- 委托业务逻辑给 `PreviewManager`
|
||||
|
||||
**关键方法**:
|
||||
```typescript
|
||||
async onOpen() // 视图打开
|
||||
async onClose() // 视图关闭
|
||||
async setFile(file) // 设置文件
|
||||
async refresh() // 刷新预览
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### preview-manager.ts ★
|
||||
**角色**:中央调度器(核心)
|
||||
**职责**:
|
||||
- 创建和管理所有子组件
|
||||
- 协调平台切换
|
||||
- 管理文件渲染
|
||||
- 统一对外接口
|
||||
|
||||
**关键方法**:
|
||||
```typescript
|
||||
async build() // 构建界面
|
||||
private switchPlatform(platform) // 平台切换(唯一入口)
|
||||
async setFile(file) // 设置文件
|
||||
async refresh() // 刷新预览
|
||||
private renderForWechat(file) // 渲染微信
|
||||
private renderForXiaohongshu(file) // 渲染小红书
|
||||
destroy() // 清理资源
|
||||
```
|
||||
|
||||
**创建流程**:
|
||||
```typescript
|
||||
constructor(container, app, render)
|
||||
↓
|
||||
async build()
|
||||
├─ createPlatformChooser()
|
||||
├─ createWechatPreview()
|
||||
└─ createXiaohongshuPreview()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### platform-chooser.ts
|
||||
**角色**:平台选择 UI 组件
|
||||
**职责**:
|
||||
- 渲染平台选择下拉框
|
||||
- 处理用户选择事件
|
||||
- 触发平台切换回调
|
||||
|
||||
**关键方法**:
|
||||
```typescript
|
||||
render() // 渲染 UI
|
||||
setOnChange(callback) // 设置回调
|
||||
switchPlatform(platform) // 程序化切换
|
||||
getCurrentPlatform() // 获取当前平台
|
||||
```
|
||||
|
||||
**使用示例**:
|
||||
```typescript
|
||||
const chooser = new PlatformChooser(container);
|
||||
chooser.setOnChange((platform) => {
|
||||
console.log('切换到:', platform);
|
||||
});
|
||||
chooser.render();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### wechat/wechat-preview.ts
|
||||
**角色**:微信公众号预览实现
|
||||
**职责**:
|
||||
- 渲染微信专属工具栏
|
||||
- 处理微信相关操作
|
||||
- 管理微信公众号配置
|
||||
|
||||
**关键方法**:
|
||||
```typescript
|
||||
build() // 构建 UI
|
||||
show() // 显示
|
||||
hide() // 隐藏
|
||||
updateStyleAndHighlight() // 更新样式
|
||||
destroy() // 清理
|
||||
|
||||
// 待实现
|
||||
uploadImages() // 上传图片
|
||||
postArticle() // 发布草稿
|
||||
exportHTML() // 导出 HTML
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### xiaohongshu/xhs-preview.ts
|
||||
**角色**:小红书预览实现
|
||||
**职责**:
|
||||
- 渲染小红书专属界面
|
||||
- 处理分页和切图
|
||||
- 管理小红书样式
|
||||
|
||||
**关键方法**:
|
||||
```typescript
|
||||
build() // 构建 UI
|
||||
show() // 显示
|
||||
hide() // 隐藏
|
||||
async renderArticle(html, file) // 渲染文章
|
||||
destroy() // 清理
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 调用关系图
|
||||
|
||||
```
|
||||
PreviewView (视图容器)
|
||||
│
|
||||
├─ holds ─> PreviewManager (协调者)
|
||||
│ │
|
||||
│ ├─ creates ─> PlatformChooser
|
||||
│ │ │
|
||||
│ │ └─ onChange callback ─┐
|
||||
│ │ │
|
||||
│ ├─ creates ─> WechatPreview │
|
||||
│ │ │ │
|
||||
│ │ ├─ onRefreshCallback ─┤
|
||||
│ │ └─ onAppIdChange ─────┤
|
||||
│ │ │
|
||||
│ └─ creates ─> XhsPreview │
|
||||
│ │ │
|
||||
│ ├─ onRefreshCallback ─────┤
|
||||
│ ├─ onPublishCallback ─────┤
|
||||
│ └─ onPlatformChange ──────┤
|
||||
│ │
|
||||
└──────────────────────────── all callbacks handled ─────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 常见任务示例
|
||||
|
||||
### 1. 添加新平台(如抖音)
|
||||
|
||||
**步骤一**:创建预览组件
|
||||
```typescript
|
||||
// src/douyin/douyin-preview.ts
|
||||
export class DouyinPreview {
|
||||
container: HTMLElement;
|
||||
app: any;
|
||||
|
||||
constructor(container: HTMLElement, app: any) {
|
||||
this.container = container;
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
build(): void {
|
||||
// 构建抖音专属 UI
|
||||
}
|
||||
|
||||
show(): void {
|
||||
this.container.style.display = 'flex';
|
||||
}
|
||||
|
||||
hide(): void {
|
||||
this.container.style.display = 'none';
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
// 清理资源
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**步骤二**:添加到支持列表
|
||||
```typescript
|
||||
// platform-chooser.ts
|
||||
const SUPPORTED_PLATFORMS: PlatformInfo[] = [
|
||||
{ value: 'wechat', label: '微信公众号', icon: '📱' },
|
||||
{ value: 'xiaohongshu', label: '小红书', icon: '📔' },
|
||||
{ value: 'douyin', label: '抖音', icon: '🎵' } // ← 新增
|
||||
];
|
||||
|
||||
// 更新类型定义
|
||||
export type PlatformType = 'wechat' | 'xiaohongshu' | 'douyin';
|
||||
```
|
||||
|
||||
**步骤三**:集成到 PreviewManager
|
||||
```typescript
|
||||
// preview-manager.ts
|
||||
import { DouyinPreview } from './douyin/douyin-preview';
|
||||
|
||||
export class PreviewManager {
|
||||
private douyinPreview: DouyinPreview | null = null;
|
||||
|
||||
private createDouyinPreview(): void {
|
||||
const container = this.mainDiv!.createDiv({ cls: 'douyin-preview-container' });
|
||||
this.douyinPreview = new DouyinPreview(container, this.app);
|
||||
this.douyinPreview.build();
|
||||
}
|
||||
|
||||
private async switchPlatform(platform: PlatformType): Promise<void> {
|
||||
// ... 现有代码
|
||||
|
||||
if (platform === 'douyin') {
|
||||
this.showDouyin();
|
||||
this.hideWechat();
|
||||
this.hideXiaohongshu();
|
||||
|
||||
if (this.currentFile) {
|
||||
await this.renderForDouyin(this.currentFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async renderForDouyin(file: TFile): Promise<void> {
|
||||
// 实现抖音渲染逻辑
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. 修改平台切换逻辑
|
||||
|
||||
**位置**:`preview-manager.ts`
|
||||
**方法**:`switchPlatform()`
|
||||
|
||||
```typescript
|
||||
private async switchPlatform(platform: PlatformType): Promise<void> {
|
||||
console.log(`切换平台: ${this.currentPlatform} → ${platform}`);
|
||||
|
||||
const previousPlatform = this.currentPlatform;
|
||||
this.currentPlatform = platform;
|
||||
|
||||
// 更新 UI
|
||||
this.platformChooser?.switchPlatform(platform);
|
||||
|
||||
// 根据平台显示/隐藏
|
||||
if (platform === 'wechat') {
|
||||
this.showWechat();
|
||||
this.hideXiaohongshu();
|
||||
// 如果需要,重新渲染
|
||||
if (this.currentFile && previousPlatform !== 'wechat') {
|
||||
await this.renderForWechat(this.currentFile);
|
||||
}
|
||||
} else if (platform === 'xiaohongshu') {
|
||||
this.showXiaohongshu();
|
||||
this.hideWechat();
|
||||
if (this.currentFile && previousPlatform !== 'xiaohongshu') {
|
||||
await this.renderForXiaohongshu(this.currentFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. 添加新的回调函数
|
||||
|
||||
**场景**:在微信预览中添加新的操作按钮
|
||||
|
||||
**步骤一**:在 WechatPreview 中定义回调
|
||||
```typescript
|
||||
// wechat-preview.ts
|
||||
export class WechatPreview {
|
||||
onCustomActionCallback?: () => Promise<void>;
|
||||
|
||||
private buildToolbar() {
|
||||
// ... 现有代码
|
||||
|
||||
const customBtn = lineDiv.createEl('button', {
|
||||
text: '自定义操作',
|
||||
cls: 'toolbar-button'
|
||||
});
|
||||
customBtn.onclick = async () => {
|
||||
if (this.onCustomActionCallback) {
|
||||
await this.onCustomActionCallback();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**步骤二**:在 PreviewManager 中设置回调
|
||||
```typescript
|
||||
// preview-manager.ts
|
||||
private createWechatPreview(): void {
|
||||
// ... 现有代码
|
||||
|
||||
this.wechatPreview.onCustomActionCallback = async () => {
|
||||
await this.handleCustomAction();
|
||||
};
|
||||
}
|
||||
|
||||
private async handleCustomAction(): Promise<void> {
|
||||
// 实现自定义操作逻辑
|
||||
console.log('执行自定义操作');
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. 监听文件变化
|
||||
|
||||
**位置**:`preview-view.ts`
|
||||
**方法**:`registerEventListeners()`
|
||||
|
||||
```typescript
|
||||
private registerEventListeners(): void {
|
||||
// 监听文件切换
|
||||
this.listeners.push(
|
||||
this.app.workspace.on('file-open', async (file: TFile | null) => {
|
||||
if (this.manager) {
|
||||
await this.manager.setFile(file);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// 监听文件修改
|
||||
this.listeners.push(
|
||||
this.app.vault.on('modify', async (file) => {
|
||||
if (file instanceof TFile) {
|
||||
const currentFile = this.manager?.getCurrentFile();
|
||||
if (currentFile && currentFile.path === file.path) {
|
||||
await this.manager?.refresh();
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// 添加新的事件监听
|
||||
this.listeners.push(
|
||||
this.app.workspace.on('your-custom-event', async (data) => {
|
||||
// 处理自定义事件
|
||||
})
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 调试技巧
|
||||
|
||||
### 1. 查看平台切换流程
|
||||
|
||||
在 `preview-manager.ts` 中添加日志:
|
||||
|
||||
```typescript
|
||||
private async switchPlatform(platform: PlatformType): Promise<void> {
|
||||
console.log(`[PreviewManager] 切换平台: ${this.currentPlatform} → ${platform}`);
|
||||
console.log('[PreviewManager] 当前文件:', this.currentFile?.path);
|
||||
|
||||
// ... 现有代码
|
||||
|
||||
console.log('[PreviewManager] 平台切换完成');
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 检查组件状态
|
||||
|
||||
在浏览器控制台中:
|
||||
|
||||
```javascript
|
||||
// 查看所有预览视图
|
||||
app.workspace.getLeavesOfType('note-preview')
|
||||
|
||||
// 获取 PreviewView 实例
|
||||
const leaf = app.workspace.getLeavesOfType('note-preview')[0]
|
||||
const previewView = leaf.view
|
||||
|
||||
// 查看 PreviewManager 状态(通过 private 访问需要技巧)
|
||||
console.log(previewView.manager)
|
||||
```
|
||||
|
||||
### 3. 断点调试
|
||||
|
||||
在关键方法中设置断点:
|
||||
- `PreviewManager.switchPlatform()`
|
||||
- `PreviewManager.setFile()`
|
||||
- `PreviewManager.renderForWechat()`
|
||||
- `PreviewManager.renderForXiaohongshu()`
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
### 1. 回调函数必须在构建前设置
|
||||
|
||||
```typescript
|
||||
// ✅ 正确
|
||||
this.wechatPreview = new WechatPreview(...);
|
||||
this.wechatPreview.onRefreshCallback = async () => { ... };
|
||||
this.wechatPreview.build();
|
||||
|
||||
// ❌ 错误(回调可能不会生效)
|
||||
this.wechatPreview = new WechatPreview(...);
|
||||
this.wechatPreview.build();
|
||||
this.wechatPreview.onRefreshCallback = async () => { ... };
|
||||
```
|
||||
|
||||
### 2. 平台切换不要直接修改 currentPlatform
|
||||
|
||||
```typescript
|
||||
// ❌ 错误(绕过了协调逻辑)
|
||||
previewManager.currentPlatform = 'xiaohongshu';
|
||||
|
||||
// ✅ 正确(通过 switchPlatform)
|
||||
await previewManager.switchPlatform('xiaohongshu');
|
||||
```
|
||||
|
||||
### 3. 清理资源
|
||||
|
||||
在组件销毁时必须清理资源:
|
||||
|
||||
```typescript
|
||||
destroy(): void {
|
||||
// 清理 DOM 引用
|
||||
this.container = null as any;
|
||||
|
||||
// 清理子组件
|
||||
this.wechatPreview?.destroy();
|
||||
this.xhsPreview?.destroy();
|
||||
|
||||
// 清理回调
|
||||
this.onRefreshCallback = undefined;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 相关文档
|
||||
|
||||
- [完整重构总结](./ARCHITECTURE_REFACTORING_COMPLETE.md)
|
||||
- [架构对比](./ARCHITECTURE_COMPARISON.md)
|
||||
- [平台重构总结](./PLATFORM_REFACTORING_SUMMARY.md)
|
||||
|
||||
---
|
||||
|
||||
**最后更新**:2025年1月
|
||||
**架构版本**:v2.0(引入 PreviewManager)
|
||||
Reference in New Issue
Block a user