ywb-office-preview 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +198 -0
- package/lib/index.cjs.js +135 -0
- package/lib/index.css +5 -0
- package/lib/index.js +135 -0
- package/lib/types/index.d.ts +88 -0
- package/office-preview/assets/deps-Db5o6o29.js +5 -0
- package/office-preview/assets/index-CayzP9YK.css +1 -0
- package/office-preview/assets/index-D5bO9emD.js +1 -0
- package/office-preview/assets/vue-office-docx-Bx6VTAU0.js +33 -0
- package/office-preview/assets/vue-office-docx-DlzDd1un.css +1 -0
- package/office-preview/assets/vue-office-excel-BGtZg_F9.js +198 -0
- package/office-preview/assets/vue-office-excel-D2SrlbN3.css +1 -0
- package/office-preview/assets/vue-office-pdf-Dz0sk0VW.js +5 -0
- package/office-preview/assets/vue-office-pptx-ox0f8gib.js +98 -0
- package/office-preview/favicon.svg +7 -0
- package/office-preview/index.html +21 -0
- package/package.json +67 -0
- package/webpack.js +21 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 杨文彬
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Vue Office 文件预览组件
|
|
2
|
+
|
|
3
|
+
一个基于 Vue 2 的 Office 文件在线预览组件,支持 PDF、Word、Excel、PowerPoint 等常见办公文档的在线预览。
|
|
4
|
+
|
|
5
|
+
## 目标
|
|
6
|
+
`@vue-office`是一个非常方便的文件预览组件,但是依赖也很大,如果直接在项目中依赖,则增加了很多额外依赖,相对应带来的问题:
|
|
7
|
+
- 浏览器加载需要优化,如何分包,如何懒加载
|
|
8
|
+
- `webpack` 或 `vite` 需要配置对应的文件,相对会降低开发时的构建工具的处理速度
|
|
9
|
+
|
|
10
|
+
## 解决方案
|
|
11
|
+
采用 iframe 隔离方案:
|
|
12
|
+
1. 将 `@vue-office` 的代码编译到 iframe 中,打包到 `office-preview` 目录下
|
|
13
|
+
2. `vue` 组件通过 `iframe` 和 `office-preview` 下的代码交互
|
|
14
|
+
3. 使用 `copy-webpack-plugin` 或 `vite-plugin-static-copy` 实现开发时动态代理`iframe`
|
|
15
|
+
|
|
16
|
+
## 架构设计
|
|
17
|
+
|
|
18
|
+
```mermaid
|
|
19
|
+
graph TD
|
|
20
|
+
A[Vue 主应用] -->|postMessage| B[iframe 容器]
|
|
21
|
+
B -->|加载| C[office-preview 应用]
|
|
22
|
+
C -->|文件类型判断| D[文件类型判断模块]
|
|
23
|
+
D -->|PDF| E[PDF 预览]
|
|
24
|
+
D -->|Word| F[Word 预览]
|
|
25
|
+
D -->|Excel| G[Excel 预览]
|
|
26
|
+
D -->|PPT| H[PPT 预览]
|
|
27
|
+
|
|
28
|
+
subgraph 主应用
|
|
29
|
+
A
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
subgraph 预览应用
|
|
33
|
+
B
|
|
34
|
+
C
|
|
35
|
+
D
|
|
36
|
+
E
|
|
37
|
+
F
|
|
38
|
+
G
|
|
39
|
+
H
|
|
40
|
+
end
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 核心模块说明
|
|
44
|
+
|
|
45
|
+
1. **主应用模块**
|
|
46
|
+
- Vue 组件封装
|
|
47
|
+
- iframe 通信管理
|
|
48
|
+
- 文件 URL 处理
|
|
49
|
+
|
|
50
|
+
2. **预览应用模块**
|
|
51
|
+
- 文件类型判断
|
|
52
|
+
- 预览组件加载
|
|
53
|
+
- 文件内容渲染
|
|
54
|
+
|
|
55
|
+
3. **通信模块**
|
|
56
|
+
- postMessage 消息处理
|
|
57
|
+
- 状态同步
|
|
58
|
+
- 错误处理
|
|
59
|
+
|
|
60
|
+
## 功能特点
|
|
61
|
+
- 📄 支持多种文件格式预览
|
|
62
|
+
- PDF 文件(.pdf)
|
|
63
|
+
- Word 文档(.doc, .docx)
|
|
64
|
+
- Excel 表格(.xls, .xlsx)
|
|
65
|
+
- PowerPoint 演示文稿(.ppt, .pptx)
|
|
66
|
+
- 🔍 智能文件类型识别
|
|
67
|
+
- 通过文件扩展名快速判断
|
|
68
|
+
- 通过文件内容(magic number)精确判断
|
|
69
|
+
- 支持新旧版 Office 文件格式
|
|
70
|
+
- 🎨 美观的界面设计
|
|
71
|
+
- 自适应容器大小
|
|
72
|
+
- 响应式布局
|
|
73
|
+
- 优雅的错误提示
|
|
74
|
+
- ⚡ 高性能实现
|
|
75
|
+
- 按需加载预览组件
|
|
76
|
+
- 优化的文件类型判断逻辑
|
|
77
|
+
- 完善的错误处理机制
|
|
78
|
+
|
|
79
|
+
## 技术栈
|
|
80
|
+
|
|
81
|
+
- Vue 2
|
|
82
|
+
- TypeScript
|
|
83
|
+
- vue-office 系列组件
|
|
84
|
+
- @vue-office/pdf
|
|
85
|
+
- @vue-office/docx
|
|
86
|
+
- @vue-office/excel
|
|
87
|
+
- @vue-office/pptx
|
|
88
|
+
|
|
89
|
+
## 安装使用
|
|
90
|
+
|
|
91
|
+
1. 安装依赖
|
|
92
|
+
```bash
|
|
93
|
+
npm install ywb-office-preview
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
2. 引入组件
|
|
97
|
+
```vue
|
|
98
|
+
<template>
|
|
99
|
+
<file-preview :src="fileUrl" />
|
|
100
|
+
</template>
|
|
101
|
+
|
|
102
|
+
<script setup>
|
|
103
|
+
import FilePreview from './components/FilePreview.vue'
|
|
104
|
+
</script>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## 组件属性
|
|
108
|
+
|
|
109
|
+
| 属性名 | 类型 | 必填 | 默认值 | 说明 |
|
|
110
|
+
|--------|--------|------|--------|----------------|
|
|
111
|
+
| fileUrl | String | 是 | - | 文件访问地址 |
|
|
112
|
+
| fileType | String | 否 | `null` | 文件类型 |
|
|
113
|
+
| frameUrl | String | 否 | `./office-preview/index.html` | 预览iframe的地址 |
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
## 文件类型判断逻辑
|
|
117
|
+
|
|
118
|
+
1. 扩展名判断(快速)
|
|
119
|
+
- 通过文件 URL 后缀快速判断文件类型
|
|
120
|
+
- 支持常见文件扩展名
|
|
121
|
+
|
|
122
|
+
2. 内容判断(精确)
|
|
123
|
+
- PDF: `%PDF` 文件头
|
|
124
|
+
- DOCX/XLSX/PPTX: ZIP 文件头 + 内容类型判断
|
|
125
|
+
- 旧版 Office 文件: 复合文档格式判断
|
|
126
|
+
|
|
127
|
+
## 示例代码
|
|
128
|
+
|
|
129
|
+
```vue
|
|
130
|
+
<template>
|
|
131
|
+
<div class="preview-container">
|
|
132
|
+
<file-preview
|
|
133
|
+
:src="fileUrl"
|
|
134
|
+
width="800px"
|
|
135
|
+
height="600px"
|
|
136
|
+
/>
|
|
137
|
+
</div>
|
|
138
|
+
</template>
|
|
139
|
+
|
|
140
|
+
<script setup>
|
|
141
|
+
import { ref } from 'vue'
|
|
142
|
+
import FilePreview from './components/FilePreview.vue'
|
|
143
|
+
|
|
144
|
+
const fileUrl = ref('https://example.com/document.pdf')
|
|
145
|
+
</script>
|
|
146
|
+
|
|
147
|
+
<style scoped>
|
|
148
|
+
.preview-container {
|
|
149
|
+
width: 100%;
|
|
150
|
+
height: 800px;
|
|
151
|
+
}
|
|
152
|
+
</style>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## 开发指南
|
|
156
|
+
|
|
157
|
+
### 本地开发
|
|
158
|
+
1. 克隆项目
|
|
159
|
+
```bash
|
|
160
|
+
git clone https://gitee.com/as1314/office-preview.git
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
2. 安装依赖
|
|
164
|
+
```bash
|
|
165
|
+
npm install
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
3. 启动开发服务器
|
|
169
|
+
```bash
|
|
170
|
+
npm run dev
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 构建部署
|
|
174
|
+
1. 构建全部(库 + 预览应用)
|
|
175
|
+
```bash
|
|
176
|
+
npm run build
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
2. 仅构建库(输出 lib/)
|
|
180
|
+
```bash
|
|
181
|
+
npm run build:lib
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
3. 仅构建预览应用(输出 office-preview/)
|
|
185
|
+
```bash
|
|
186
|
+
npm run build:html
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## 贡献指南
|
|
190
|
+
|
|
191
|
+
欢迎提交 Issue 和 Pull Request 来帮助改进这个项目。
|
|
192
|
+
|
|
193
|
+
## 许可证
|
|
194
|
+
|
|
195
|
+
MIT License
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
package/lib/index.cjs.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const vue = require("vue");
|
|
4
|
+
const uuidv4 = () => {
|
|
5
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
|
|
6
|
+
var r = Math.random() * 16 | 0, v = c == "x" ? r : r & 3 | 8;
|
|
7
|
+
return v.toString(16);
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
class FrameChannel {
|
|
11
|
+
constructor(iframe) {
|
|
12
|
+
this.callbackMap = /* @__PURE__ */ new Map();
|
|
13
|
+
this.eventMap = /* @__PURE__ */ new Map();
|
|
14
|
+
this.win = (iframe == null ? void 0 : iframe.contentWindow) || window;
|
|
15
|
+
this.onMessage = this.onMessage.bind(this);
|
|
16
|
+
this.win.addEventListener("message", this.onMessage);
|
|
17
|
+
}
|
|
18
|
+
emit(event, ...args) {
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
const callbackId = uuidv4();
|
|
21
|
+
this.callbackMap.set(callbackId, resolve);
|
|
22
|
+
this.win.postMessage(
|
|
23
|
+
{
|
|
24
|
+
event,
|
|
25
|
+
args,
|
|
26
|
+
callbackId
|
|
27
|
+
},
|
|
28
|
+
"*"
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
addEventListener(event, callback) {
|
|
33
|
+
this.eventMap.set(event, callback);
|
|
34
|
+
}
|
|
35
|
+
onMessage(event) {
|
|
36
|
+
const { event: eventName, args, callbackId } = event.data;
|
|
37
|
+
if (/^callback:/.test(eventName)) {
|
|
38
|
+
const backId = eventName.replace(/^callback:/, "");
|
|
39
|
+
const callback = this.callbackMap.get(backId);
|
|
40
|
+
if (callback) {
|
|
41
|
+
callback(args);
|
|
42
|
+
this.callbackMap.delete(backId);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const cb = this.eventMap.get(eventName);
|
|
47
|
+
if (cb) {
|
|
48
|
+
const resp = (results) => {
|
|
49
|
+
this.win.postMessage(
|
|
50
|
+
{
|
|
51
|
+
event: `callback:${callbackId}`,
|
|
52
|
+
args: results
|
|
53
|
+
},
|
|
54
|
+
"*"
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
cb(resp, ...args);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const SupportedFileType = ["excel", "pdf", "ppt", "word"];
|
|
62
|
+
const SupportedFileExtension = [
|
|
63
|
+
{
|
|
64
|
+
type: "excel",
|
|
65
|
+
extension: [".xls", ".xlsx"]
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
type: "pdf",
|
|
69
|
+
extension: [".pdf"]
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
type: "word",
|
|
73
|
+
extension: [".doc", ".docx"]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
type: "ppt",
|
|
77
|
+
extension: [".ppt", ".pptx"]
|
|
78
|
+
}
|
|
79
|
+
];
|
|
80
|
+
class PreviewFrameChannel extends FrameChannel {
|
|
81
|
+
}
|
|
82
|
+
class OfficePreviewChannel extends FrameChannel {
|
|
83
|
+
}
|
|
84
|
+
const OfficePreview = vue.defineComponent({
|
|
85
|
+
name: "OfficePreview",
|
|
86
|
+
props: {
|
|
87
|
+
fileUrl: {
|
|
88
|
+
type: String
|
|
89
|
+
},
|
|
90
|
+
frameUrl: {
|
|
91
|
+
type: String,
|
|
92
|
+
default: "./office-preview/index.html"
|
|
93
|
+
},
|
|
94
|
+
fileType: {
|
|
95
|
+
type: String,
|
|
96
|
+
default: null
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
emits: {},
|
|
100
|
+
setup(props, context) {
|
|
101
|
+
const frameRef = vue.ref();
|
|
102
|
+
const channelRef = vue.ref();
|
|
103
|
+
vue.onMounted(() => {
|
|
104
|
+
const channel = new OfficePreviewChannel(frameRef.value);
|
|
105
|
+
channel.addEventListener("loaded", () => {
|
|
106
|
+
channelRef.value = channel;
|
|
107
|
+
context.emit("loaded", channel);
|
|
108
|
+
updateFile();
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
const updateFile = () => {
|
|
112
|
+
var _a;
|
|
113
|
+
if (props.fileUrl) {
|
|
114
|
+
(_a = channelRef.value) == null ? void 0 : _a.emit("loadFile", props.fileUrl, props.fileType);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
vue.watch(() => props.fileUrl, updateFile);
|
|
118
|
+
vue.watch(() => props.fileType, updateFile);
|
|
119
|
+
return () => {
|
|
120
|
+
return vue.h("iframe", {
|
|
121
|
+
"ref": frameRef,
|
|
122
|
+
"attrs": {
|
|
123
|
+
"src": props.frameUrl
|
|
124
|
+
},
|
|
125
|
+
"class": "office-preview"
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
exports.FrameChannel = FrameChannel;
|
|
131
|
+
exports.OfficePreview = OfficePreview;
|
|
132
|
+
exports.OfficePreviewChannel = OfficePreviewChannel;
|
|
133
|
+
exports.PreviewFrameChannel = PreviewFrameChannel;
|
|
134
|
+
exports.SupportedFileExtension = SupportedFileExtension;
|
|
135
|
+
exports.SupportedFileType = SupportedFileType;
|
package/lib/index.css
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { defineComponent, ref, onMounted, watch, h } from "vue";
|
|
2
|
+
const uuidv4 = () => {
|
|
3
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
|
|
4
|
+
var r = Math.random() * 16 | 0, v = c == "x" ? r : r & 3 | 8;
|
|
5
|
+
return v.toString(16);
|
|
6
|
+
});
|
|
7
|
+
};
|
|
8
|
+
class FrameChannel {
|
|
9
|
+
constructor(iframe) {
|
|
10
|
+
this.callbackMap = /* @__PURE__ */ new Map();
|
|
11
|
+
this.eventMap = /* @__PURE__ */ new Map();
|
|
12
|
+
this.win = (iframe == null ? void 0 : iframe.contentWindow) || window;
|
|
13
|
+
this.onMessage = this.onMessage.bind(this);
|
|
14
|
+
this.win.addEventListener("message", this.onMessage);
|
|
15
|
+
}
|
|
16
|
+
emit(event, ...args) {
|
|
17
|
+
return new Promise((resolve) => {
|
|
18
|
+
const callbackId = uuidv4();
|
|
19
|
+
this.callbackMap.set(callbackId, resolve);
|
|
20
|
+
this.win.postMessage(
|
|
21
|
+
{
|
|
22
|
+
event,
|
|
23
|
+
args,
|
|
24
|
+
callbackId
|
|
25
|
+
},
|
|
26
|
+
"*"
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
addEventListener(event, callback) {
|
|
31
|
+
this.eventMap.set(event, callback);
|
|
32
|
+
}
|
|
33
|
+
onMessage(event) {
|
|
34
|
+
const { event: eventName, args, callbackId } = event.data;
|
|
35
|
+
if (/^callback:/.test(eventName)) {
|
|
36
|
+
const backId = eventName.replace(/^callback:/, "");
|
|
37
|
+
const callback = this.callbackMap.get(backId);
|
|
38
|
+
if (callback) {
|
|
39
|
+
callback(args);
|
|
40
|
+
this.callbackMap.delete(backId);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const cb = this.eventMap.get(eventName);
|
|
45
|
+
if (cb) {
|
|
46
|
+
const resp = (results) => {
|
|
47
|
+
this.win.postMessage(
|
|
48
|
+
{
|
|
49
|
+
event: `callback:${callbackId}`,
|
|
50
|
+
args: results
|
|
51
|
+
},
|
|
52
|
+
"*"
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
cb(resp, ...args);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const SupportedFileType = ["excel", "pdf", "ppt", "word"];
|
|
60
|
+
const SupportedFileExtension = [
|
|
61
|
+
{
|
|
62
|
+
type: "excel",
|
|
63
|
+
extension: [".xls", ".xlsx"]
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
type: "pdf",
|
|
67
|
+
extension: [".pdf"]
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
type: "word",
|
|
71
|
+
extension: [".doc", ".docx"]
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
type: "ppt",
|
|
75
|
+
extension: [".ppt", ".pptx"]
|
|
76
|
+
}
|
|
77
|
+
];
|
|
78
|
+
class PreviewFrameChannel extends FrameChannel {
|
|
79
|
+
}
|
|
80
|
+
class OfficePreviewChannel extends FrameChannel {
|
|
81
|
+
}
|
|
82
|
+
const OfficePreview = defineComponent({
|
|
83
|
+
name: "OfficePreview",
|
|
84
|
+
props: {
|
|
85
|
+
fileUrl: {
|
|
86
|
+
type: String
|
|
87
|
+
},
|
|
88
|
+
frameUrl: {
|
|
89
|
+
type: String,
|
|
90
|
+
default: "./office-preview/index.html"
|
|
91
|
+
},
|
|
92
|
+
fileType: {
|
|
93
|
+
type: String,
|
|
94
|
+
default: null
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
emits: {},
|
|
98
|
+
setup(props, context) {
|
|
99
|
+
const frameRef = ref();
|
|
100
|
+
const channelRef = ref();
|
|
101
|
+
onMounted(() => {
|
|
102
|
+
const channel = new OfficePreviewChannel(frameRef.value);
|
|
103
|
+
channel.addEventListener("loaded", () => {
|
|
104
|
+
channelRef.value = channel;
|
|
105
|
+
context.emit("loaded", channel);
|
|
106
|
+
updateFile();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
const updateFile = () => {
|
|
110
|
+
var _a;
|
|
111
|
+
if (props.fileUrl) {
|
|
112
|
+
(_a = channelRef.value) == null ? void 0 : _a.emit("loadFile", props.fileUrl, props.fileType);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
watch(() => props.fileUrl, updateFile);
|
|
116
|
+
watch(() => props.fileType, updateFile);
|
|
117
|
+
return () => {
|
|
118
|
+
return h("iframe", {
|
|
119
|
+
"ref": frameRef,
|
|
120
|
+
"attrs": {
|
|
121
|
+
"src": props.frameUrl
|
|
122
|
+
},
|
|
123
|
+
"class": "office-preview"
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
export {
|
|
129
|
+
FrameChannel,
|
|
130
|
+
OfficePreview,
|
|
131
|
+
OfficePreviewChannel,
|
|
132
|
+
PreviewFrameChannel,
|
|
133
|
+
SupportedFileExtension,
|
|
134
|
+
SupportedFileType
|
|
135
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { ComponentOptionsMixin } from 'vue';
|
|
2
|
+
import { DefineComponent } from 'vue';
|
|
3
|
+
import { ExtractPropTypes } from 'vue';
|
|
4
|
+
import { PropType } from 'vue';
|
|
5
|
+
|
|
6
|
+
declare type EventArgs<EventMap, EventName extends EventNames<EventMap>> = EventMap[EventName] extends (...args: any[]) => any ? Parameters<EventMap[EventName]> : any[];
|
|
7
|
+
|
|
8
|
+
declare type EventCallback<EventMap, EventName extends EventNames<EventMap>> = (args: EventResponse<EventMap, EventName>) => void;
|
|
9
|
+
|
|
10
|
+
declare type EventNames<EventMap> = EventMap extends {
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
} ? keyof EventMap : any;
|
|
13
|
+
|
|
14
|
+
declare type EventResponse<EventMap, EventName extends EventNames<EventMap>> = EventMap[EventName] extends (...args: any[]) => any ? ReturnType<EventMap[EventName]> : never;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* iframe 通信channel
|
|
18
|
+
* @template EventsType 支持发送的事件类型
|
|
19
|
+
* @template ListenersType 支持监听的事件类型
|
|
20
|
+
*/
|
|
21
|
+
export declare class FrameChannel<EventsType = string | symbol, ListenersType = string | symbol> {
|
|
22
|
+
private win;
|
|
23
|
+
private callbackMap;
|
|
24
|
+
private eventMap;
|
|
25
|
+
constructor(iframe?: HTMLIFrameElement);
|
|
26
|
+
emit<T extends EventNames<EventsType>>(event: T, ...args: EventArgs<EventsType, T>): Promise<EventResponse<EventsType, T>>;
|
|
27
|
+
addEventListener<T extends EventNames<ListenersType>>(event: T, callback: (resolve: EventCallback<ListenersType, T>, ...args: EventArgs<ListenersType, T>) => void): void;
|
|
28
|
+
private onMessage;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export declare const OfficePreview: DefineComponent< {
|
|
32
|
+
fileUrl: {
|
|
33
|
+
type: StringConstructor;
|
|
34
|
+
};
|
|
35
|
+
frameUrl: {
|
|
36
|
+
type: StringConstructor;
|
|
37
|
+
default: string;
|
|
38
|
+
};
|
|
39
|
+
fileType: {
|
|
40
|
+
type: PropType<SupportedFileTypes>;
|
|
41
|
+
default: null;
|
|
42
|
+
};
|
|
43
|
+
}, () => JSX.Element, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {
|
|
44
|
+
loaded: (channel: OfficePreviewChannel) => any;
|
|
45
|
+
}, string, Readonly<ExtractPropTypes< {
|
|
46
|
+
fileUrl: {
|
|
47
|
+
type: StringConstructor;
|
|
48
|
+
};
|
|
49
|
+
frameUrl: {
|
|
50
|
+
type: StringConstructor;
|
|
51
|
+
default: string;
|
|
52
|
+
};
|
|
53
|
+
fileType: {
|
|
54
|
+
type: PropType<SupportedFileTypes>;
|
|
55
|
+
default: null;
|
|
56
|
+
};
|
|
57
|
+
}>>, {
|
|
58
|
+
frameUrl: string;
|
|
59
|
+
fileType: SupportedFileTypes;
|
|
60
|
+
}>;
|
|
61
|
+
|
|
62
|
+
export declare class OfficePreviewChannel extends FrameChannel<PreviewComponentEvents, PreviewFrameEvents> {
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export declare interface PreviewComponentEvents {
|
|
66
|
+
loadFile?: (fileUrl: string, fileType?: SupportedFileTypes) => void;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export declare class PreviewFrameChannel extends FrameChannel<PreviewFrameEvents, PreviewComponentEvents> {
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export declare interface PreviewFrameEvents {
|
|
73
|
+
loaded?: () => void;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 文件类型映射表
|
|
78
|
+
*/
|
|
79
|
+
export declare const SupportedFileExtension: {
|
|
80
|
+
type: SupportedFileTypes;
|
|
81
|
+
extension: string[];
|
|
82
|
+
}[];
|
|
83
|
+
|
|
84
|
+
export declare const SupportedFileType: SupportedFileTypes[];
|
|
85
|
+
|
|
86
|
+
declare type SupportedFileTypes = "word" | "excel" | "ppt" | "pdf";
|
|
87
|
+
|
|
88
|
+
export { }
|