feat:完成通过自定义Collabora插件实现页面跳转
This commit is contained in:
@@ -13,7 +13,9 @@ lib/
|
||||
├── highlight.ts # 高亮功能
|
||||
├── navigation.ts # 导航/跳转功能
|
||||
├── zoom.ts # 缩放功能
|
||||
└── document.ts # 文档操作
|
||||
├── document.ts # 文档操作
|
||||
├── pageInfo.ts # 页数信息获取
|
||||
└── gotoPage.ts # 自定义页面跳转(不使用 UNO 命令)
|
||||
```
|
||||
|
||||
## 功能模块
|
||||
@@ -31,9 +33,6 @@ lib/
|
||||
|
||||
### 4. navigation.ts - 导航/跳转功能
|
||||
- `unoScrollToTop(iframeWindow)` - 滚动到文档开头(带焦点请求)
|
||||
- `unoGotoPage(iframeWindow, pageNumber)` - 跳转到指定页面
|
||||
- `unoFirstPage(iframeWindow)` - 跳转到第一页
|
||||
- `unoLastPage(iframeWindow)` - 跳转到最后一页
|
||||
|
||||
### 5. zoom.ts - 缩放功能
|
||||
- `unoZoomPlus(iframeWindow)` - 放大文档
|
||||
@@ -49,6 +48,10 @@ lib/
|
||||
- `getPageInfoFromCollabora()` - 从 Collabora 内部直接获取页数(仅 iframe 内部可用)
|
||||
- `PageInfo` 接口 - 页数信息类型定义
|
||||
|
||||
### 8. gotoPage.ts - 自定义页面跳转(不使用 UNO 命令)
|
||||
- `customGotoPage(iframeWindow, pageNumber)` - 跳转到指定页面(使用自定义 PostMessage 协议)
|
||||
- `GotoPageResponse` 接口 - 页面跳转响应信息类型定义
|
||||
|
||||
## 使用方式
|
||||
|
||||
### 方式 1: 从统一入口导入(推荐)
|
||||
@@ -60,6 +63,8 @@ import {
|
||||
unoHighlightText,
|
||||
unoScrollToTop,
|
||||
unoSave,
|
||||
customGotoPage,
|
||||
requestPageInfo,
|
||||
} from '~/components/collabora/lib';
|
||||
```
|
||||
|
||||
@@ -68,6 +73,8 @@ import {
|
||||
```typescript
|
||||
import { unoSearchText } from '~/components/collabora/lib/search';
|
||||
import { unoScrollToTop } from '~/components/collabora/lib/navigation';
|
||||
import { customGotoPage } from '~/components/collabora/lib/gotoPage';
|
||||
import { requestPageInfo } from '~/components/collabora/lib/pageInfo';
|
||||
```
|
||||
|
||||
## 核心工具函数
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* Collabora 自定义页面跳转模块
|
||||
*
|
||||
* 使用自定义 PostMessage 协议实现页面跳转,不依赖 UNO 命令
|
||||
*
|
||||
* @encoding UTF-8
|
||||
*/
|
||||
|
||||
/**
|
||||
* 页面跳转响应接口
|
||||
*/
|
||||
export interface GotoPageResponse {
|
||||
pageNumber: number;
|
||||
pageIndex: number;
|
||||
totalPages: number;
|
||||
currentOffset: number;
|
||||
targetOffset: number;
|
||||
scrollDelta: number;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collabora PostMessage 数据类型
|
||||
*/
|
||||
interface CollaboraMessageData {
|
||||
MessageId?: string;
|
||||
msgId?: string;
|
||||
Values?: {
|
||||
Command?: string;
|
||||
Status?: string;
|
||||
pageNumber?: number;
|
||||
pageIndex?: number;
|
||||
totalPages?: number;
|
||||
currentOffset?: number;
|
||||
targetOffset?: number;
|
||||
scrollDelta?: number;
|
||||
timestamp?: number;
|
||||
Error?: string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
args?: {
|
||||
Command?: string;
|
||||
Status?: string;
|
||||
pageNumber?: number;
|
||||
pageIndex?: number;
|
||||
totalPages?: number;
|
||||
currentOffset?: number;
|
||||
targetOffset?: number;
|
||||
scrollDelta?: number;
|
||||
timestamp?: number;
|
||||
Error?: string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 PostMessage 数据
|
||||
*/
|
||||
function parseMessageData(data: unknown): CollaboraMessageData {
|
||||
if (typeof data === 'string') {
|
||||
return JSON.parse(data) as CollaboraMessageData;
|
||||
}
|
||||
return data as CollaboraMessageData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到指定页面 (自定义实现,不使用 UNO 命令)
|
||||
*
|
||||
* 使用自定义 custompostMessage 插件实现页面跳转。
|
||||
* 注意: Collabora 的页码是从 0 开始的,但此函数接受从 1 开始的页码。
|
||||
*
|
||||
* @param iframeWindow - iframe 的 contentWindow
|
||||
* @param pageNumber - 页码 (从1开始)
|
||||
* @returns Promise,解析为跳转响应信息
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const response = await customGotoPage(iframeWindow, 5);
|
||||
* console.log(`成功跳转到第 ${response.pageNumber} 页`);
|
||||
* ```
|
||||
*/
|
||||
export async function customGotoPage(
|
||||
iframeWindow: Window,
|
||||
pageNumber: number
|
||||
): Promise<GotoPageResponse> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
cleanup();
|
||||
reject(new Error('页面跳转超时'));
|
||||
}, 5000);
|
||||
|
||||
const handleMessage = (event: MessageEvent) => {
|
||||
try {
|
||||
if (event.source !== iframeWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = parseMessageData(event.data);
|
||||
|
||||
// bundle.js 的 _postMessage 会将消息转换为:
|
||||
// { MessageId: 'custompostMessage_Resp', Values: { Command: 'GOTO_PAGE', ... } }
|
||||
if (
|
||||
data.MessageId === 'custompostMessage_Resp' &&
|
||||
data.Values?.Command === 'GOTO_PAGE'
|
||||
) {
|
||||
clearTimeout(timeout);
|
||||
cleanup();
|
||||
|
||||
if (data.Values.Status === 'success') {
|
||||
const response: GotoPageResponse = {
|
||||
pageNumber: data.Values.pageNumber || pageNumber,
|
||||
pageIndex: data.Values.pageIndex || pageNumber - 1,
|
||||
totalPages: data.Values.totalPages || 0,
|
||||
currentOffset: data.Values.currentOffset || 0,
|
||||
targetOffset: data.Values.targetOffset || 0,
|
||||
scrollDelta: data.Values.scrollDelta || 0,
|
||||
timestamp: data.Values.timestamp || Date.now(),
|
||||
};
|
||||
resolve(response);
|
||||
} else {
|
||||
reject(new Error(data.Values.Error || '页面跳转失败'));
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
clearTimeout(timeout);
|
||||
cleanup();
|
||||
reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
const cleanup = () => {
|
||||
window.removeEventListener('message', handleMessage);
|
||||
};
|
||||
|
||||
window.addEventListener('message', handleMessage);
|
||||
|
||||
// 发送跳转请求消息
|
||||
const message = {
|
||||
MessageId: 'custompostMessage',
|
||||
Values: {
|
||||
Command: 'GOTO_PAGE',
|
||||
Args: {
|
||||
pageNumber: pageNumber,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
iframeWindow.postMessage(JSON.stringify(message), '*');
|
||||
});
|
||||
}
|
||||
@@ -16,9 +16,6 @@ export { unoHighlightText, unoRemoveHighlight, unoEscape } from './highlight';
|
||||
// 导航/跳转功能
|
||||
export {
|
||||
unoScrollToTop,
|
||||
unoGotoPage,
|
||||
unoFirstPage,
|
||||
unoLastPage,
|
||||
} from './navigation';
|
||||
|
||||
// 缩放功能
|
||||
@@ -32,3 +29,9 @@ export {
|
||||
requestPageInfo,
|
||||
type PageInfo,
|
||||
} from './pageInfo';
|
||||
|
||||
// 自定义页面跳转功能
|
||||
export {
|
||||
customGotoPage,
|
||||
type GotoPageResponse,
|
||||
} from './gotoPage';
|
||||
|
||||
@@ -31,32 +31,3 @@ export async function unoScrollToTop(iframeWindow: Window): Promise<void> {
|
||||
sendUnoCommand(iframeWindow, '.uno:GoToStartOfDoc', {});
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到指定页面
|
||||
* @param iframeWindow - iframe 的 contentWindow
|
||||
* @param pageNumber - 页码(从1开始)
|
||||
*/
|
||||
export function unoGotoPage(iframeWindow: Window, pageNumber: number): void {
|
||||
sendUnoCommand(iframeWindow, '.uno:GotoPage', {
|
||||
Page: {
|
||||
type: 'long',
|
||||
value: pageNumber,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到第一页
|
||||
* @param iframeWindow - iframe 的 contentWindow
|
||||
*/
|
||||
export function unoFirstPage(iframeWindow: Window): void {
|
||||
sendUnoCommand(iframeWindow, '.uno:FirstPage', {});
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到最后一页
|
||||
* @param iframeWindow - iframe 的 contentWindow
|
||||
*/
|
||||
export function unoLastPage(iframeWindow: Window): void {
|
||||
sendUnoCommand(iframeWindow, '.uno:LastPage', {});
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ interface CollaboraMessageData {
|
||||
currentPage?: number;
|
||||
timestamp?: number;
|
||||
pages?: number;
|
||||
currentPage?: number;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
// 原始插件返回的格式
|
||||
@@ -42,27 +41,7 @@ interface CollaboraMessageData {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collabora 全局对象类型
|
||||
*/
|
||||
interface CollaboraApp {
|
||||
map?: {
|
||||
_docLayer?: {
|
||||
_pages?: number;
|
||||
_currentPage?: number;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
[key: string]: unknown;
|
||||
};
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展 Window 类型以包含 Collabora app
|
||||
*/
|
||||
interface CollaboraWindow extends Window {
|
||||
app?: CollaboraApp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 PostMessage 数据
|
||||
|
||||
Reference in New Issue
Block a user