customer-chat-sdk 1.0.34 → 1.0.35
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/dist/core/ScreenshotManager.d.ts +34 -1
- package/dist/core/ScreenshotManager.d.ts.map +1 -1
- package/dist/customer-sdk.cjs.js +170 -0
- package/dist/customer-sdk.esm.js +170 -0
- package/dist/customer-sdk.min.js +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +3 -2
|
@@ -13,7 +13,7 @@ export interface ScreenshotOptions {
|
|
|
13
13
|
enableCORS?: boolean;
|
|
14
14
|
proxyUrl?: string;
|
|
15
15
|
useProxy?: boolean;
|
|
16
|
-
engine?: 'modern-screenshot' | 'snapdom';
|
|
16
|
+
engine?: 'modern-screenshot' | 'snapdom' | 'html2canvas';
|
|
17
17
|
corsMode?: 'simple' | 'smart' | 'proxy' | 'blob' | 'canvas-proxy' | 'ignore' | 'test-first';
|
|
18
18
|
silentMode?: boolean;
|
|
19
19
|
maxRetries?: number;
|
|
@@ -125,8 +125,41 @@ export declare class ScreenshotManager {
|
|
|
125
125
|
* 注意:snapdom 内部使用 worker 进行截图处理,会在后台线程执行,不会阻塞主线程
|
|
126
126
|
*/
|
|
127
127
|
private takeScreenshotWithSnapdom;
|
|
128
|
+
/**
|
|
129
|
+
* 使用 html2canvas 截图
|
|
130
|
+
*
|
|
131
|
+
* 优势:
|
|
132
|
+
* - 处理 SVG 和本地资源更快(不需要复杂的 Worker 通信)
|
|
133
|
+
* - 兼容性好,支持更多 CSS 特性
|
|
134
|
+
* - 跨域处理相对简单
|
|
135
|
+
*
|
|
136
|
+
* 劣势:
|
|
137
|
+
* - 在主线程执行,可能阻塞 UI(但处理速度快,影响较小)
|
|
138
|
+
* - 不支持 Worker 模式
|
|
139
|
+
*
|
|
140
|
+
* 适用场景:
|
|
141
|
+
* - 页面包含大量 SVG 图标
|
|
142
|
+
* - 本地资源较多
|
|
143
|
+
* - 需要快速截图
|
|
144
|
+
*/
|
|
145
|
+
private takeScreenshotWithHtml2Canvas;
|
|
128
146
|
/**
|
|
129
147
|
* 使用 modern-screenshot 截图(启用 Worker)
|
|
148
|
+
*
|
|
149
|
+
* 优势:
|
|
150
|
+
* - 使用 Worker,不阻塞主线程 UI
|
|
151
|
+
* - 支持并发处理
|
|
152
|
+
* - 适合复杂页面
|
|
153
|
+
*
|
|
154
|
+
* 劣势:
|
|
155
|
+
* - 处理 SVG 和本地资源较慢(Worker 通信开销)
|
|
156
|
+
* - 配置相对复杂
|
|
157
|
+
* - 需要处理 Worker URL
|
|
158
|
+
*
|
|
159
|
+
* 适用场景:
|
|
160
|
+
* - 复杂页面,需要不阻塞 UI
|
|
161
|
+
* - 需要高质量截图
|
|
162
|
+
* - 页面资源较少
|
|
130
163
|
*/
|
|
131
164
|
private takeScreenshotWithModernScreenshot;
|
|
132
165
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScreenshotManager.d.ts","sourceRoot":"","sources":["../../src/core/ScreenshotManager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ScreenshotManager.d.ts","sourceRoot":"","sources":["../../src/core/ScreenshotManager.ts"],"names":[],"mappings":"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"}
|
package/dist/customer-sdk.cjs.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
var html2canvas = require('html2canvas');
|
|
6
|
+
|
|
5
7
|
// 直接使用base64字符串,避免打包后路径问题
|
|
6
8
|
const iconImage = 'data:image/png;base64,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';
|
|
7
9
|
class IconManager {
|
|
@@ -6904,6 +6906,9 @@ class ScreenshotManager {
|
|
|
6904
6906
|
if (selectedEngine === 'snapdom') {
|
|
6905
6907
|
dataUrl = await this.takeScreenshotWithSnapdom(this.targetElement);
|
|
6906
6908
|
}
|
|
6909
|
+
else if (selectedEngine === 'html2canvas') {
|
|
6910
|
+
dataUrl = await this.takeScreenshotWithHtml2Canvas(this.targetElement);
|
|
6911
|
+
}
|
|
6907
6912
|
else {
|
|
6908
6913
|
// 默认使用 modern-screenshot
|
|
6909
6914
|
dataUrl = await this.takeScreenshotWithModernScreenshot(this.targetElement);
|
|
@@ -7066,8 +7071,173 @@ class ScreenshotManager {
|
|
|
7066
7071
|
throw error;
|
|
7067
7072
|
}
|
|
7068
7073
|
}
|
|
7074
|
+
/**
|
|
7075
|
+
* 使用 html2canvas 截图
|
|
7076
|
+
*
|
|
7077
|
+
* 优势:
|
|
7078
|
+
* - 处理 SVG 和本地资源更快(不需要复杂的 Worker 通信)
|
|
7079
|
+
* - 兼容性好,支持更多 CSS 特性
|
|
7080
|
+
* - 跨域处理相对简单
|
|
7081
|
+
*
|
|
7082
|
+
* 劣势:
|
|
7083
|
+
* - 在主线程执行,可能阻塞 UI(但处理速度快,影响较小)
|
|
7084
|
+
* - 不支持 Worker 模式
|
|
7085
|
+
*
|
|
7086
|
+
* 适用场景:
|
|
7087
|
+
* - 页面包含大量 SVG 图标
|
|
7088
|
+
* - 本地资源较多
|
|
7089
|
+
* - 需要快速截图
|
|
7090
|
+
*/
|
|
7091
|
+
async takeScreenshotWithHtml2Canvas(element) {
|
|
7092
|
+
if (!this.options.silentMode) {
|
|
7093
|
+
console.log('📸 使用 html2canvas 引擎截图...');
|
|
7094
|
+
}
|
|
7095
|
+
try {
|
|
7096
|
+
// 检查元素是否存在和可见
|
|
7097
|
+
const rect = element.getBoundingClientRect();
|
|
7098
|
+
if (rect.width === 0 || rect.height === 0) {
|
|
7099
|
+
throw new Error('元素尺寸为 0,无法截图');
|
|
7100
|
+
}
|
|
7101
|
+
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
7102
|
+
const isLowEndDevice = navigator.hardwareConcurrency && navigator.hardwareConcurrency <= 4;
|
|
7103
|
+
// 计算压缩后的尺寸
|
|
7104
|
+
let elementWidth = element.scrollWidth || element.clientWidth || element.offsetWidth;
|
|
7105
|
+
let elementHeight = element.scrollHeight || element.clientHeight || element.offsetHeight;
|
|
7106
|
+
if (element === document.body || element === document.documentElement) {
|
|
7107
|
+
elementWidth = Math.max(element.scrollWidth, element.offsetWidth, document.documentElement.scrollWidth, document.documentElement.offsetWidth, window.innerWidth);
|
|
7108
|
+
elementHeight = Math.max(element.scrollHeight, element.offsetHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight, window.innerHeight);
|
|
7109
|
+
}
|
|
7110
|
+
const { width, height } = this.calculateCompressedSize(elementWidth, elementHeight, this.options.maxWidth, this.options.maxHeight);
|
|
7111
|
+
const finalWidth = width < elementWidth ? width : Math.min(elementWidth, this.options.maxWidth);
|
|
7112
|
+
const finalHeight = height < elementHeight ? height : Math.min(elementHeight, this.options.maxHeight);
|
|
7113
|
+
// html2canvas 质量设置(0-1)
|
|
7114
|
+
const finalQuality = isMobile || isLowEndDevice
|
|
7115
|
+
? Math.max(this.options.quality * 0.65, 0.2)
|
|
7116
|
+
: this.options.quality;
|
|
7117
|
+
// html2canvas 配置选项
|
|
7118
|
+
const options = {
|
|
7119
|
+
// 基本配置
|
|
7120
|
+
backgroundColor: '#ffffff',
|
|
7121
|
+
scale: this.options.scale !== 1 ? (isMobile ? 0.7 : this.options.scale) : (isMobile ? 0.7 : 1),
|
|
7122
|
+
useCORS: this.options.enableCORS,
|
|
7123
|
+
allowTaint: !this.options.enableCORS, // 如果启用 CORS,不允许 taint
|
|
7124
|
+
logging: !this.options.silentMode,
|
|
7125
|
+
width: finalWidth,
|
|
7126
|
+
height: finalHeight,
|
|
7127
|
+
// 性能优化
|
|
7128
|
+
removeContainer: true, // 截图后移除临时容器
|
|
7129
|
+
imageTimeout: this.options.imageLoadTimeout || 5000,
|
|
7130
|
+
// 忽略某些元素(可选,提升性能)
|
|
7131
|
+
ignoreElements: (element) => {
|
|
7132
|
+
// 忽略隐藏元素
|
|
7133
|
+
const style = window.getComputedStyle(element);
|
|
7134
|
+
if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') {
|
|
7135
|
+
return true;
|
|
7136
|
+
}
|
|
7137
|
+
return false;
|
|
7138
|
+
},
|
|
7139
|
+
};
|
|
7140
|
+
// html2canvas 不支持直接的 proxy 选项,需要通过 onclone 钩子处理图片
|
|
7141
|
+
// 如果配置了代理服务器,在克隆时替换图片 URL
|
|
7142
|
+
if (this.options.useProxy && this.options.proxyUrl && this.options.proxyUrl.trim() !== '') {
|
|
7143
|
+
options.onclone = (clonedDoc) => {
|
|
7144
|
+
// 在克隆的文档中,替换所有跨域图片的 src
|
|
7145
|
+
const images = clonedDoc.querySelectorAll('img');
|
|
7146
|
+
images.forEach((img) => {
|
|
7147
|
+
const originalSrc = img.getAttribute('src');
|
|
7148
|
+
if (!originalSrc)
|
|
7149
|
+
return;
|
|
7150
|
+
// 检查是否是跨域图片
|
|
7151
|
+
try {
|
|
7152
|
+
const imgUrl = new URL(originalSrc, window.location.href);
|
|
7153
|
+
if (imgUrl.origin === window.location.origin) {
|
|
7154
|
+
return; // 同源图片,不需要处理
|
|
7155
|
+
}
|
|
7156
|
+
}
|
|
7157
|
+
catch {
|
|
7158
|
+
// URL 解析失败,可能是相对路径,继续处理
|
|
7159
|
+
}
|
|
7160
|
+
// 检查缓存
|
|
7161
|
+
const cachedDataUrl = this.getCachedImage(originalSrc);
|
|
7162
|
+
if (cachedDataUrl) {
|
|
7163
|
+
img.src = cachedDataUrl;
|
|
7164
|
+
return;
|
|
7165
|
+
}
|
|
7166
|
+
// 对于跨域图片,使用代理 URL
|
|
7167
|
+
// html2canvas 会自动处理,但我们可以预先处理
|
|
7168
|
+
// 注意:html2canvas 会自己处理图片加载,这里主要是为了缓存
|
|
7169
|
+
});
|
|
7170
|
+
};
|
|
7171
|
+
}
|
|
7172
|
+
if (!this.options.silentMode) {
|
|
7173
|
+
console.log(`📸 html2canvas 配置: 尺寸 ${finalWidth}x${finalHeight}, 质量 ${finalQuality.toFixed(2)}, 缩放 ${options.scale}`);
|
|
7174
|
+
}
|
|
7175
|
+
// 执行截图
|
|
7176
|
+
const canvas = await html2canvas(element, options);
|
|
7177
|
+
// 根据输出格式转换
|
|
7178
|
+
let mimeType = 'image/png';
|
|
7179
|
+
let finalQualityForExport = undefined;
|
|
7180
|
+
if (this.options.outputFormat === 'webp' && !isMobile) {
|
|
7181
|
+
try {
|
|
7182
|
+
const testCanvas = document.createElement('canvas');
|
|
7183
|
+
testCanvas.width = 1;
|
|
7184
|
+
testCanvas.height = 1;
|
|
7185
|
+
const testDataUrl = testCanvas.toDataURL('image/webp');
|
|
7186
|
+
if (testDataUrl.indexOf('webp') !== -1) {
|
|
7187
|
+
mimeType = 'image/webp';
|
|
7188
|
+
finalQualityForExport = finalQuality;
|
|
7189
|
+
}
|
|
7190
|
+
}
|
|
7191
|
+
catch {
|
|
7192
|
+
mimeType = 'image/jpeg';
|
|
7193
|
+
finalQualityForExport = finalQuality;
|
|
7194
|
+
}
|
|
7195
|
+
}
|
|
7196
|
+
else if (this.options.outputFormat === 'jpeg') {
|
|
7197
|
+
mimeType = 'image/jpeg';
|
|
7198
|
+
finalQualityForExport = finalQuality;
|
|
7199
|
+
}
|
|
7200
|
+
// 转换为 data URL
|
|
7201
|
+
const dataUrl = mimeType === 'image/png'
|
|
7202
|
+
? canvas.toDataURL(mimeType)
|
|
7203
|
+
: canvas.toDataURL(mimeType, finalQualityForExport);
|
|
7204
|
+
// 验证结果
|
|
7205
|
+
if (!dataUrl || dataUrl.length < 100) {
|
|
7206
|
+
throw new Error('生成的截图数据无效或过短');
|
|
7207
|
+
}
|
|
7208
|
+
if (!this.options.silentMode) {
|
|
7209
|
+
console.log(`📸 html2canvas 截图成功!格式: ${this.options.outputFormat}, 尺寸: ${canvas.width}x${canvas.height}`);
|
|
7210
|
+
}
|
|
7211
|
+
return dataUrl;
|
|
7212
|
+
}
|
|
7213
|
+
catch (error) {
|
|
7214
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
7215
|
+
if (!this.options.silentMode) {
|
|
7216
|
+
console.error('📸 html2canvas 截图失败:', errorMessage);
|
|
7217
|
+
if (errorMessage.includes('CORS') || errorMessage.includes('cross-origin')) {
|
|
7218
|
+
console.warn('📸 💡 建议:配置 proxyUrl 选项处理跨域图片');
|
|
7219
|
+
}
|
|
7220
|
+
}
|
|
7221
|
+
throw error;
|
|
7222
|
+
}
|
|
7223
|
+
}
|
|
7069
7224
|
/**
|
|
7070
7225
|
* 使用 modern-screenshot 截图(启用 Worker)
|
|
7226
|
+
*
|
|
7227
|
+
* 优势:
|
|
7228
|
+
* - 使用 Worker,不阻塞主线程 UI
|
|
7229
|
+
* - 支持并发处理
|
|
7230
|
+
* - 适合复杂页面
|
|
7231
|
+
*
|
|
7232
|
+
* 劣势:
|
|
7233
|
+
* - 处理 SVG 和本地资源较慢(Worker 通信开销)
|
|
7234
|
+
* - 配置相对复杂
|
|
7235
|
+
* - 需要处理 Worker URL
|
|
7236
|
+
*
|
|
7237
|
+
* 适用场景:
|
|
7238
|
+
* - 复杂页面,需要不阻塞 UI
|
|
7239
|
+
* - 需要高质量截图
|
|
7240
|
+
* - 页面资源较少
|
|
7071
7241
|
*/
|
|
7072
7242
|
async takeScreenshotWithModernScreenshot(element) {
|
|
7073
7243
|
if (!this.options.silentMode) {
|
package/dist/customer-sdk.esm.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import html2canvas from 'html2canvas';
|
|
2
|
+
|
|
1
3
|
// 直接使用base64字符串,避免打包后路径问题
|
|
2
4
|
const iconImage = 'data:image/png;base64,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';
|
|
3
5
|
class IconManager {
|
|
@@ -6900,6 +6902,9 @@ class ScreenshotManager {
|
|
|
6900
6902
|
if (selectedEngine === 'snapdom') {
|
|
6901
6903
|
dataUrl = await this.takeScreenshotWithSnapdom(this.targetElement);
|
|
6902
6904
|
}
|
|
6905
|
+
else if (selectedEngine === 'html2canvas') {
|
|
6906
|
+
dataUrl = await this.takeScreenshotWithHtml2Canvas(this.targetElement);
|
|
6907
|
+
}
|
|
6903
6908
|
else {
|
|
6904
6909
|
// 默认使用 modern-screenshot
|
|
6905
6910
|
dataUrl = await this.takeScreenshotWithModernScreenshot(this.targetElement);
|
|
@@ -7062,8 +7067,173 @@ class ScreenshotManager {
|
|
|
7062
7067
|
throw error;
|
|
7063
7068
|
}
|
|
7064
7069
|
}
|
|
7070
|
+
/**
|
|
7071
|
+
* 使用 html2canvas 截图
|
|
7072
|
+
*
|
|
7073
|
+
* 优势:
|
|
7074
|
+
* - 处理 SVG 和本地资源更快(不需要复杂的 Worker 通信)
|
|
7075
|
+
* - 兼容性好,支持更多 CSS 特性
|
|
7076
|
+
* - 跨域处理相对简单
|
|
7077
|
+
*
|
|
7078
|
+
* 劣势:
|
|
7079
|
+
* - 在主线程执行,可能阻塞 UI(但处理速度快,影响较小)
|
|
7080
|
+
* - 不支持 Worker 模式
|
|
7081
|
+
*
|
|
7082
|
+
* 适用场景:
|
|
7083
|
+
* - 页面包含大量 SVG 图标
|
|
7084
|
+
* - 本地资源较多
|
|
7085
|
+
* - 需要快速截图
|
|
7086
|
+
*/
|
|
7087
|
+
async takeScreenshotWithHtml2Canvas(element) {
|
|
7088
|
+
if (!this.options.silentMode) {
|
|
7089
|
+
console.log('📸 使用 html2canvas 引擎截图...');
|
|
7090
|
+
}
|
|
7091
|
+
try {
|
|
7092
|
+
// 检查元素是否存在和可见
|
|
7093
|
+
const rect = element.getBoundingClientRect();
|
|
7094
|
+
if (rect.width === 0 || rect.height === 0) {
|
|
7095
|
+
throw new Error('元素尺寸为 0,无法截图');
|
|
7096
|
+
}
|
|
7097
|
+
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
7098
|
+
const isLowEndDevice = navigator.hardwareConcurrency && navigator.hardwareConcurrency <= 4;
|
|
7099
|
+
// 计算压缩后的尺寸
|
|
7100
|
+
let elementWidth = element.scrollWidth || element.clientWidth || element.offsetWidth;
|
|
7101
|
+
let elementHeight = element.scrollHeight || element.clientHeight || element.offsetHeight;
|
|
7102
|
+
if (element === document.body || element === document.documentElement) {
|
|
7103
|
+
elementWidth = Math.max(element.scrollWidth, element.offsetWidth, document.documentElement.scrollWidth, document.documentElement.offsetWidth, window.innerWidth);
|
|
7104
|
+
elementHeight = Math.max(element.scrollHeight, element.offsetHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight, window.innerHeight);
|
|
7105
|
+
}
|
|
7106
|
+
const { width, height } = this.calculateCompressedSize(elementWidth, elementHeight, this.options.maxWidth, this.options.maxHeight);
|
|
7107
|
+
const finalWidth = width < elementWidth ? width : Math.min(elementWidth, this.options.maxWidth);
|
|
7108
|
+
const finalHeight = height < elementHeight ? height : Math.min(elementHeight, this.options.maxHeight);
|
|
7109
|
+
// html2canvas 质量设置(0-1)
|
|
7110
|
+
const finalQuality = isMobile || isLowEndDevice
|
|
7111
|
+
? Math.max(this.options.quality * 0.65, 0.2)
|
|
7112
|
+
: this.options.quality;
|
|
7113
|
+
// html2canvas 配置选项
|
|
7114
|
+
const options = {
|
|
7115
|
+
// 基本配置
|
|
7116
|
+
backgroundColor: '#ffffff',
|
|
7117
|
+
scale: this.options.scale !== 1 ? (isMobile ? 0.7 : this.options.scale) : (isMobile ? 0.7 : 1),
|
|
7118
|
+
useCORS: this.options.enableCORS,
|
|
7119
|
+
allowTaint: !this.options.enableCORS, // 如果启用 CORS,不允许 taint
|
|
7120
|
+
logging: !this.options.silentMode,
|
|
7121
|
+
width: finalWidth,
|
|
7122
|
+
height: finalHeight,
|
|
7123
|
+
// 性能优化
|
|
7124
|
+
removeContainer: true, // 截图后移除临时容器
|
|
7125
|
+
imageTimeout: this.options.imageLoadTimeout || 5000,
|
|
7126
|
+
// 忽略某些元素(可选,提升性能)
|
|
7127
|
+
ignoreElements: (element) => {
|
|
7128
|
+
// 忽略隐藏元素
|
|
7129
|
+
const style = window.getComputedStyle(element);
|
|
7130
|
+
if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') {
|
|
7131
|
+
return true;
|
|
7132
|
+
}
|
|
7133
|
+
return false;
|
|
7134
|
+
},
|
|
7135
|
+
};
|
|
7136
|
+
// html2canvas 不支持直接的 proxy 选项,需要通过 onclone 钩子处理图片
|
|
7137
|
+
// 如果配置了代理服务器,在克隆时替换图片 URL
|
|
7138
|
+
if (this.options.useProxy && this.options.proxyUrl && this.options.proxyUrl.trim() !== '') {
|
|
7139
|
+
options.onclone = (clonedDoc) => {
|
|
7140
|
+
// 在克隆的文档中,替换所有跨域图片的 src
|
|
7141
|
+
const images = clonedDoc.querySelectorAll('img');
|
|
7142
|
+
images.forEach((img) => {
|
|
7143
|
+
const originalSrc = img.getAttribute('src');
|
|
7144
|
+
if (!originalSrc)
|
|
7145
|
+
return;
|
|
7146
|
+
// 检查是否是跨域图片
|
|
7147
|
+
try {
|
|
7148
|
+
const imgUrl = new URL(originalSrc, window.location.href);
|
|
7149
|
+
if (imgUrl.origin === window.location.origin) {
|
|
7150
|
+
return; // 同源图片,不需要处理
|
|
7151
|
+
}
|
|
7152
|
+
}
|
|
7153
|
+
catch {
|
|
7154
|
+
// URL 解析失败,可能是相对路径,继续处理
|
|
7155
|
+
}
|
|
7156
|
+
// 检查缓存
|
|
7157
|
+
const cachedDataUrl = this.getCachedImage(originalSrc);
|
|
7158
|
+
if (cachedDataUrl) {
|
|
7159
|
+
img.src = cachedDataUrl;
|
|
7160
|
+
return;
|
|
7161
|
+
}
|
|
7162
|
+
// 对于跨域图片,使用代理 URL
|
|
7163
|
+
// html2canvas 会自动处理,但我们可以预先处理
|
|
7164
|
+
// 注意:html2canvas 会自己处理图片加载,这里主要是为了缓存
|
|
7165
|
+
});
|
|
7166
|
+
};
|
|
7167
|
+
}
|
|
7168
|
+
if (!this.options.silentMode) {
|
|
7169
|
+
console.log(`📸 html2canvas 配置: 尺寸 ${finalWidth}x${finalHeight}, 质量 ${finalQuality.toFixed(2)}, 缩放 ${options.scale}`);
|
|
7170
|
+
}
|
|
7171
|
+
// 执行截图
|
|
7172
|
+
const canvas = await html2canvas(element, options);
|
|
7173
|
+
// 根据输出格式转换
|
|
7174
|
+
let mimeType = 'image/png';
|
|
7175
|
+
let finalQualityForExport = undefined;
|
|
7176
|
+
if (this.options.outputFormat === 'webp' && !isMobile) {
|
|
7177
|
+
try {
|
|
7178
|
+
const testCanvas = document.createElement('canvas');
|
|
7179
|
+
testCanvas.width = 1;
|
|
7180
|
+
testCanvas.height = 1;
|
|
7181
|
+
const testDataUrl = testCanvas.toDataURL('image/webp');
|
|
7182
|
+
if (testDataUrl.indexOf('webp') !== -1) {
|
|
7183
|
+
mimeType = 'image/webp';
|
|
7184
|
+
finalQualityForExport = finalQuality;
|
|
7185
|
+
}
|
|
7186
|
+
}
|
|
7187
|
+
catch {
|
|
7188
|
+
mimeType = 'image/jpeg';
|
|
7189
|
+
finalQualityForExport = finalQuality;
|
|
7190
|
+
}
|
|
7191
|
+
}
|
|
7192
|
+
else if (this.options.outputFormat === 'jpeg') {
|
|
7193
|
+
mimeType = 'image/jpeg';
|
|
7194
|
+
finalQualityForExport = finalQuality;
|
|
7195
|
+
}
|
|
7196
|
+
// 转换为 data URL
|
|
7197
|
+
const dataUrl = mimeType === 'image/png'
|
|
7198
|
+
? canvas.toDataURL(mimeType)
|
|
7199
|
+
: canvas.toDataURL(mimeType, finalQualityForExport);
|
|
7200
|
+
// 验证结果
|
|
7201
|
+
if (!dataUrl || dataUrl.length < 100) {
|
|
7202
|
+
throw new Error('生成的截图数据无效或过短');
|
|
7203
|
+
}
|
|
7204
|
+
if (!this.options.silentMode) {
|
|
7205
|
+
console.log(`📸 html2canvas 截图成功!格式: ${this.options.outputFormat}, 尺寸: ${canvas.width}x${canvas.height}`);
|
|
7206
|
+
}
|
|
7207
|
+
return dataUrl;
|
|
7208
|
+
}
|
|
7209
|
+
catch (error) {
|
|
7210
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
7211
|
+
if (!this.options.silentMode) {
|
|
7212
|
+
console.error('📸 html2canvas 截图失败:', errorMessage);
|
|
7213
|
+
if (errorMessage.includes('CORS') || errorMessage.includes('cross-origin')) {
|
|
7214
|
+
console.warn('📸 💡 建议:配置 proxyUrl 选项处理跨域图片');
|
|
7215
|
+
}
|
|
7216
|
+
}
|
|
7217
|
+
throw error;
|
|
7218
|
+
}
|
|
7219
|
+
}
|
|
7065
7220
|
/**
|
|
7066
7221
|
* 使用 modern-screenshot 截图(启用 Worker)
|
|
7222
|
+
*
|
|
7223
|
+
* 优势:
|
|
7224
|
+
* - 使用 Worker,不阻塞主线程 UI
|
|
7225
|
+
* - 支持并发处理
|
|
7226
|
+
* - 适合复杂页面
|
|
7227
|
+
*
|
|
7228
|
+
* 劣势:
|
|
7229
|
+
* - 处理 SVG 和本地资源较慢(Worker 通信开销)
|
|
7230
|
+
* - 配置相对复杂
|
|
7231
|
+
* - 需要处理 Worker URL
|
|
7232
|
+
*
|
|
7233
|
+
* 适用场景:
|
|
7234
|
+
* - 复杂页面,需要不阻塞 UI
|
|
7235
|
+
* - 需要高质量截图
|
|
7236
|
+
* - 页面资源较少
|
|
7067
7237
|
*/
|
|
7068
7238
|
async takeScreenshotWithModernScreenshot(element) {
|
|
7069
7239
|
if (!this.options.silentMode) {
|