customer-chat-sdk 1.0.72 → 1.0.74
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.
|
@@ -29,6 +29,8 @@ export interface ScreenshotOptions {
|
|
|
29
29
|
skipLargeImages?: boolean;
|
|
30
30
|
workerNumber?: number;
|
|
31
31
|
workerUrl?: string;
|
|
32
|
+
drawImageInterval?: number;
|
|
33
|
+
backgroundColor?: string;
|
|
32
34
|
}
|
|
33
35
|
/**
|
|
34
36
|
* 上传配置接口
|
|
@@ -71,11 +73,6 @@ export declare class ScreenshotManager {
|
|
|
71
73
|
private worker;
|
|
72
74
|
private screenshotTimer;
|
|
73
75
|
private screenshotContext;
|
|
74
|
-
private contextElement;
|
|
75
|
-
private contextOptionsHash;
|
|
76
|
-
private contextContentHash;
|
|
77
|
-
private contextLastUpdateTime;
|
|
78
|
-
private contextMaxAge;
|
|
79
76
|
private isScreenshotInProgress;
|
|
80
77
|
private screenshotQueue;
|
|
81
78
|
private isProcessingQueue;
|
|
@@ -98,11 +95,6 @@ export declare class ScreenshotManager {
|
|
|
98
95
|
* 设置目标元素
|
|
99
96
|
*/
|
|
100
97
|
setTargetElement(element: HTMLElement | null): void;
|
|
101
|
-
/**
|
|
102
|
-
* 计算 DOM 内容哈希(用于检测内容变化)
|
|
103
|
-
* 通过检测图片 URL、尺寸、文本内容等来判断内容是否变化
|
|
104
|
-
*/
|
|
105
|
-
private calculateContentHash;
|
|
106
98
|
/**
|
|
107
99
|
* 设置消息监听
|
|
108
100
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScreenshotManager.d.ts","sourceRoot":"","sources":["../../src/core/ScreenshotManager.ts"],"names":[],"mappings":"AAWA;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAA;IACtC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,mBAAmB,GAAG,SAAS,GAAG,aAAa,CAAA;IACxD,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,cAAc,GAAG,QAAQ,GAAG,YAAY,CAAA;IAC3F,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,aAAa,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAA;IACvC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;
|
|
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
|
@@ -14322,11 +14322,6 @@ class ScreenshotManager {
|
|
|
14322
14322
|
this.screenshotTimer = null;
|
|
14323
14323
|
// modern-screenshot Worker 上下文(用于复用,避免频繁创建和销毁)
|
|
14324
14324
|
this.screenshotContext = null;
|
|
14325
|
-
this.contextElement = null; // 当前 context 对应的元素
|
|
14326
|
-
this.contextOptionsHash = ''; // context 配置的哈希值,用于判断是否需要重新创建
|
|
14327
|
-
this.contextContentHash = ''; // DOM 内容哈希值,用于检测内容变化
|
|
14328
|
-
this.contextLastUpdateTime = 0; // context 最后更新时间
|
|
14329
|
-
this.contextMaxAge = 5000; // context 最大存活时间(5秒),超过后强制刷新(缩短到5秒,确保内容及时更新)
|
|
14330
14325
|
// 截图锁,防止并发截图
|
|
14331
14326
|
this.isScreenshotInProgress = false;
|
|
14332
14327
|
// 截图队列(用于处理频繁的截图请求)
|
|
@@ -14384,7 +14379,10 @@ class ScreenshotManager {
|
|
|
14384
14379
|
fetchPriority: options.fetchPriority ?? 'high', // 默认高优先级
|
|
14385
14380
|
maxImageSize: options.maxImageSize ?? 5, // 不使用代理时,单个图片最大尺寸(MB),默认5MB
|
|
14386
14381
|
skipLargeImages: options.skipLargeImages ?? true, // 不使用代理时,是否跳过过大的图片,默认true(跳过)
|
|
14387
|
-
workerNumber: options.workerNumber ?? undefined // modern-screenshot Worker 数量,默认自动计算(undefined 表示自动)
|
|
14382
|
+
workerNumber: options.workerNumber ?? undefined, // modern-screenshot Worker 数量,默认自动计算(undefined 表示自动)
|
|
14383
|
+
workerUrl: options.workerUrl ?? undefined, // modern-screenshot Worker URL,默认自动
|
|
14384
|
+
drawImageInterval: options.drawImageInterval ?? 20, // modern-screenshot drawImageInterval,默认 20ms
|
|
14385
|
+
backgroundColor: options.backgroundColor ?? '#ffffff', // modern-screenshot backgroundColor,默认 '#ffffff'
|
|
14388
14386
|
};
|
|
14389
14387
|
this.setupMessageListener();
|
|
14390
14388
|
this.setupVisibilityChangeListener();
|
|
@@ -14422,82 +14420,10 @@ class ScreenshotManager {
|
|
|
14422
14420
|
// 忽略清理错误
|
|
14423
14421
|
}
|
|
14424
14422
|
this.screenshotContext = null;
|
|
14425
|
-
this.contextElement = null;
|
|
14426
|
-
this.contextOptionsHash = '';
|
|
14427
|
-
this.contextContentHash = '';
|
|
14428
|
-
this.contextLastUpdateTime = 0;
|
|
14429
14423
|
}
|
|
14430
14424
|
}
|
|
14431
14425
|
this.targetElement = element;
|
|
14432
14426
|
}
|
|
14433
|
-
/**
|
|
14434
|
-
* 计算 DOM 内容哈希(用于检测内容变化)
|
|
14435
|
-
* 通过检测图片 URL、尺寸、文本内容等来判断内容是否变化
|
|
14436
|
-
*/
|
|
14437
|
-
calculateContentHash(element) {
|
|
14438
|
-
try {
|
|
14439
|
-
// 收集关键内容信息
|
|
14440
|
-
const contentInfo = {
|
|
14441
|
-
// 收集所有图片 URL 和尺寸(用于检测图片变化)
|
|
14442
|
-
// 只收集可见的图片,避免隐藏图片影响哈希
|
|
14443
|
-
images: Array.from(element.querySelectorAll('img'))
|
|
14444
|
-
.filter(img => {
|
|
14445
|
-
const style = window.getComputedStyle(img);
|
|
14446
|
-
return style.display !== 'none' && style.visibility !== 'hidden';
|
|
14447
|
-
})
|
|
14448
|
-
.map(img => ({
|
|
14449
|
-
src: img.src,
|
|
14450
|
-
currentSrc: img.currentSrc || img.src, // 使用 currentSrc 检测响应式图片变化
|
|
14451
|
-
naturalWidth: img.naturalWidth,
|
|
14452
|
-
naturalHeight: img.naturalHeight,
|
|
14453
|
-
complete: img.complete // 检测图片是否加载完成
|
|
14454
|
-
})),
|
|
14455
|
-
// 收集关键文本内容(前 500 个字符,减少计算量)
|
|
14456
|
-
text: element.innerText?.substring(0, 500) || '',
|
|
14457
|
-
// 收集关键元素的类名和 ID(用于检测结构变化)
|
|
14458
|
-
// 只收集前 30 个,减少计算量
|
|
14459
|
-
structure: Array.from(element.querySelectorAll('[class], [id]'))
|
|
14460
|
-
.slice(0, 30)
|
|
14461
|
-
.map(el => ({
|
|
14462
|
-
tag: el.tagName,
|
|
14463
|
-
class: el.className,
|
|
14464
|
-
id: el.id
|
|
14465
|
-
})),
|
|
14466
|
-
// 收集背景图片 URL(只收集前 10 个)
|
|
14467
|
-
backgrounds: Array.from(element.querySelectorAll('[style*="background"]'))
|
|
14468
|
-
.slice(0, 10)
|
|
14469
|
-
.map(el => {
|
|
14470
|
-
try {
|
|
14471
|
-
const style = window.getComputedStyle(el);
|
|
14472
|
-
return {
|
|
14473
|
-
backgroundImage: style.backgroundImage,
|
|
14474
|
-
backgroundSize: style.backgroundSize
|
|
14475
|
-
};
|
|
14476
|
-
}
|
|
14477
|
-
catch {
|
|
14478
|
-
return null;
|
|
14479
|
-
}
|
|
14480
|
-
})
|
|
14481
|
-
.filter(Boolean)
|
|
14482
|
-
};
|
|
14483
|
-
// 生成哈希值(简单的 JSON 字符串哈希)
|
|
14484
|
-
const hashString = JSON.stringify(contentInfo);
|
|
14485
|
-
// 使用简单的哈希算法(FNV-1a)
|
|
14486
|
-
let hash = 2166136261;
|
|
14487
|
-
for (let i = 0; i < hashString.length; i++) {
|
|
14488
|
-
hash ^= hashString.charCodeAt(i);
|
|
14489
|
-
hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
|
|
14490
|
-
}
|
|
14491
|
-
return hash.toString(36);
|
|
14492
|
-
}
|
|
14493
|
-
catch (error) {
|
|
14494
|
-
// 如果计算失败,使用时间戳作为后备(强制刷新)
|
|
14495
|
-
if (!this.options.silentMode) {
|
|
14496
|
-
console.warn('📸 计算内容哈希失败,使用时间戳:', error);
|
|
14497
|
-
}
|
|
14498
|
-
return Date.now().toString();
|
|
14499
|
-
}
|
|
14500
|
-
}
|
|
14501
14427
|
/**
|
|
14502
14428
|
* 设置消息监听
|
|
14503
14429
|
*/
|
|
@@ -15280,6 +15206,8 @@ class ScreenshotManager {
|
|
|
15280
15206
|
useCORS: this.options.enableCORS,
|
|
15281
15207
|
allowTaint: !this.options.enableCORS, // 如果启用 CORS,不允许 taint
|
|
15282
15208
|
logging: !this.options.silentMode,
|
|
15209
|
+
foreignObjectRendering: true,
|
|
15210
|
+
removeContainer: true, // 截图后清理缓存节点
|
|
15283
15211
|
// 不设置 width 和 height,让 html2canvas 自动计算
|
|
15284
15212
|
// width: finalWidth, // ❌ 移除,会导致宽度不正确
|
|
15285
15213
|
// height: finalHeight, // ❌ 移除,会导致高度不正确
|
|
@@ -15623,21 +15551,6 @@ class ScreenshotManager {
|
|
|
15623
15551
|
console.log(`📸 窗口尺寸: ${window.innerWidth}x${window.innerHeight}`);
|
|
15624
15552
|
}
|
|
15625
15553
|
}
|
|
15626
|
-
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
15627
|
-
const isLowEndDevice = navigator.hardwareConcurrency && navigator.hardwareConcurrency <= 4;
|
|
15628
|
-
// 进一步降低质量以减少 base64 大小
|
|
15629
|
-
// 桌面设备:使用配置的质量(默认 0.3)
|
|
15630
|
-
// 移动设备/低端设备:进一步降低到 0.2(最低)
|
|
15631
|
-
const finalQuality = isMobile || isLowEndDevice
|
|
15632
|
-
? Math.max(this.options.quality * 0.65, 0.2) // 移动设备:质量 * 0.65,最低 0.2
|
|
15633
|
-
: this.options.quality; // 桌面设备:使用配置的质量(默认 0.3)
|
|
15634
|
-
// 计算压缩后的尺寸(对所有元素都应用,包括 document.body)
|
|
15635
|
-
// 这样可以避免生成过大的截图,减少 base64 大小
|
|
15636
|
-
const { width, height } = this.calculateCompressedSize(elementWidth, elementHeight, this.options.maxWidth, this.options.maxHeight);
|
|
15637
|
-
// 使用计算后的压缩尺寸(确保不超过 maxWidth/maxHeight)
|
|
15638
|
-
// 对于 body 元素,已经使用了 window.innerWidth/innerHeight,所以直接使用压缩尺寸即可
|
|
15639
|
-
const finalWidth = width;
|
|
15640
|
-
const finalHeight = height;
|
|
15641
15554
|
// 判断是否使用代理
|
|
15642
15555
|
const shouldUseProxy = this.options.useProxy && this.options.proxyUrl && this.options.proxyUrl.trim() !== '';
|
|
15643
15556
|
// 处理跨域图片的函数(仅在配置了代理时使用)
|
|
@@ -15736,6 +15649,8 @@ class ScreenshotManager {
|
|
|
15736
15649
|
else {
|
|
15737
15650
|
// 自动计算 workerNumber
|
|
15738
15651
|
const cpuCores = navigator.hardwareConcurrency || 4; // 默认假设 4 核
|
|
15652
|
+
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
15653
|
+
const isLowEndDevice = navigator.hardwareConcurrency && navigator.hardwareConcurrency <= 4;
|
|
15739
15654
|
if (isMobile || isLowEndDevice) {
|
|
15740
15655
|
// 移动设备/低端设备:使用 1 个 Worker(避免内存压力)
|
|
15741
15656
|
workerNumber = 1;
|
|
@@ -15757,282 +15672,86 @@ class ScreenshotManager {
|
|
|
15757
15672
|
}
|
|
15758
15673
|
// 限制 workerNumber 范围:1-8(避免过多 Worker 导致资源竞争)
|
|
15759
15674
|
workerNumber = Math.max(1, Math.min(8, workerNumber));
|
|
15760
|
-
//
|
|
15761
|
-
//
|
|
15762
|
-
|
|
15763
|
-
workerNumber, // Worker 数量,> 0 启用 Worker 模式
|
|
15764
|
-
quality: finalQuality, // 图片质量(0-1),已优化为更低的值以减少 base64 大小
|
|
15765
|
-
// 只有在配置了代理时才传递 fetchFn,否则让 modern-screenshot 自己处理(性能更好)
|
|
15766
|
-
...(shouldUseProxy ? {
|
|
15767
|
-
fetchFn: handleCrossOriginImage, // 使用代理服务器处理跨域图片
|
|
15768
|
-
fetch: {
|
|
15769
|
-
requestInit: {
|
|
15770
|
-
cache: 'no-cache',
|
|
15771
|
-
},
|
|
15772
|
-
bypassingCache: true,
|
|
15773
|
-
},
|
|
15774
|
-
} : {}),
|
|
15775
|
-
// 设置最大 canvas 尺寸,防止生成过大的 canvas(避免内存问题)
|
|
15776
|
-
// 参考: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas#maximum_canvas_size
|
|
15777
|
-
// 大多数浏览器限制为 16,777,216 像素(4096x4096),这里设置为更保守的值
|
|
15778
|
-
maximumCanvasSize: 16777216, // 16M 像素(约 4096x4096)
|
|
15779
|
-
// 使用 modern-screenshot 内置的 timeout(更可靠)
|
|
15780
|
-
timeout: Math.max(this.options.interval * 6, 5000),
|
|
15781
|
-
};
|
|
15782
|
-
// 限制 timeout 最多 15 秒
|
|
15783
|
-
contextOptions.timeout = Math.min(contextOptions.timeout, 15000);
|
|
15784
|
-
// 如果用户指定了 workerUrl,使用指定的 URL
|
|
15785
|
-
// 否则让 modern-screenshot 自动处理(它会尝试从 node_modules 或 CDN 加载)
|
|
15786
|
-
// 注意:在某些构建工具(如 Rollup)中,可能需要手动指定 workerUrl
|
|
15787
|
-
if (this.options.workerUrl) {
|
|
15788
|
-
contextOptions.workerUrl = this.options.workerUrl;
|
|
15789
|
-
if (!this.options.silentMode) {
|
|
15790
|
-
console.log(`📸 使用指定的 Worker URL: ${this.options.workerUrl}`);
|
|
15791
|
-
}
|
|
15792
|
-
}
|
|
15793
|
-
else {
|
|
15794
|
-
// 未指定 workerUrl 时,modern-screenshot 会自动处理
|
|
15795
|
-
// 但在某些构建环境中可能需要手动指定,可以使用 CDN 作为后备
|
|
15796
|
-
// 这里不设置 workerUrl,让 modern-screenshot 自己处理
|
|
15675
|
+
// 按照 demo 的方式:只在 context 不存在时创建,之后一直复用
|
|
15676
|
+
// 不进行复杂的检测和重新创建逻辑
|
|
15677
|
+
if (!this.screenshotContext) {
|
|
15797
15678
|
if (!this.options.silentMode) {
|
|
15798
|
-
console.log(
|
|
15679
|
+
console.log(`📸 创建截图 Worker 上下文...`);
|
|
15680
|
+
console.log(`📸 Worker 模式: ${workerNumber} 个 Worker`);
|
|
15799
15681
|
}
|
|
15800
|
-
|
|
15801
|
-
|
|
15802
|
-
|
|
15803
|
-
|
|
15804
|
-
|
|
15805
|
-
|
|
15806
|
-
|
|
15807
|
-
|
|
15808
|
-
|
|
15809
|
-
|
|
15810
|
-
|
|
15811
|
-
|
|
15812
|
-
}
|
|
15813
|
-
}
|
|
15814
|
-
|
|
15815
|
-
|
|
15816
|
-
|
|
15817
|
-
|
|
15818
|
-
|
|
15819
|
-
}
|
|
15820
|
-
// 缩放配置:使用外部传递的参数
|
|
15821
|
-
// scale < 1 会降低图片分辨率,减少 base64 大小
|
|
15822
|
-
if (this.options.scale !== undefined && this.options.scale !== 1) {
|
|
15823
|
-
contextOptions.scale = this.options.scale;
|
|
15824
|
-
}
|
|
15825
|
-
// 优化:复用 context,避免频繁创建和销毁(性能提升 20%+)
|
|
15826
|
-
// 只在元素变化、配置变化或内容变化时重新创建 context
|
|
15827
|
-
// 1. 计算配置哈希
|
|
15828
|
-
const contextOptionsHash = JSON.stringify({
|
|
15829
|
-
workerNumber,
|
|
15830
|
-
quality: finalQuality,
|
|
15831
|
-
scale: contextOptions.scale,
|
|
15832
|
-
width: contextOptions.width,
|
|
15833
|
-
height: contextOptions.height,
|
|
15834
|
-
maximumCanvasSize: contextOptions.maximumCanvasSize,
|
|
15835
|
-
timeout: contextOptions.timeout
|
|
15836
|
-
});
|
|
15837
|
-
// 2. 计算 DOM 内容哈希(检测内容变化)
|
|
15838
|
-
// 通过检测图片 URL、文本内容等来判断内容是否变化
|
|
15839
|
-
// 注意:modern-screenshot 的 context 在创建时会"快照" DOM 状态
|
|
15840
|
-
// 如果 DOM 内容变化了,必须重新创建 context 才能捕获最新内容
|
|
15841
|
-
const contentHash = this.calculateContentHash(element);
|
|
15842
|
-
// 3. 检查 context 是否过期(超过最大存活时间)
|
|
15843
|
-
// 缩短过期时间,确保频繁变化的内容能及时更新
|
|
15844
|
-
const now = Date.now();
|
|
15845
|
-
const isContextExpired = this.contextLastUpdateTime > 0 &&
|
|
15846
|
-
(now - this.contextLastUpdateTime) > this.contextMaxAge;
|
|
15847
|
-
// 4. 判断是否需要重新创建 context
|
|
15848
|
-
// 关键:如果内容哈希变化,必须重新创建 context(modern-screenshot 的限制)
|
|
15849
|
-
const needsRecreateContext = !this.screenshotContext ||
|
|
15850
|
-
this.contextElement !== element ||
|
|
15851
|
-
this.contextOptionsHash !== contextOptionsHash ||
|
|
15852
|
-
this.contextContentHash !== contentHash || // 内容变化时强制重新创建
|
|
15853
|
-
isContextExpired;
|
|
15854
|
-
if (needsRecreateContext) {
|
|
15855
|
-
if (!this.options.silentMode) {
|
|
15856
|
-
if (this.screenshotContext) {
|
|
15857
|
-
let reason = '检测到';
|
|
15858
|
-
if (this.contextElement !== element)
|
|
15859
|
-
reason += '元素变化';
|
|
15860
|
-
if (this.contextOptionsHash !== contextOptionsHash)
|
|
15861
|
-
reason += '配置变化';
|
|
15862
|
-
if (this.contextContentHash !== contentHash)
|
|
15863
|
-
reason += '内容变化';
|
|
15864
|
-
if (isContextExpired)
|
|
15865
|
-
reason += 'context 过期';
|
|
15866
|
-
console.log(`📸 ${reason},重新创建 context...`);
|
|
15867
|
-
}
|
|
15868
|
-
else {
|
|
15869
|
-
console.log(`📸 Worker 模式: ${workerNumber} 个 Worker,质量: ${finalQuality.toFixed(2)},缩放: ${contextOptions.scale || 1}`);
|
|
15682
|
+
// 简化 createContext 配置,只传必要的参数(和 demo 一致)
|
|
15683
|
+
const simpleContextOptions = {
|
|
15684
|
+
workerNumber, // Worker 数量
|
|
15685
|
+
// 只有在配置了代理时才传递 fetchFn
|
|
15686
|
+
...(shouldUseProxy ? {
|
|
15687
|
+
fetchFn: handleCrossOriginImage,
|
|
15688
|
+
fetch: {
|
|
15689
|
+
requestInit: {
|
|
15690
|
+
cache: 'no-cache',
|
|
15691
|
+
},
|
|
15692
|
+
bypassingCache: true,
|
|
15693
|
+
},
|
|
15694
|
+
} : {}),
|
|
15695
|
+
};
|
|
15696
|
+
// 如果用户指定了 workerUrl,使用指定的 URL
|
|
15697
|
+
if (this.options.workerUrl) {
|
|
15698
|
+
simpleContextOptions.workerUrl = this.options.workerUrl;
|
|
15699
|
+
if (!this.options.silentMode) {
|
|
15700
|
+
console.log(`📸 使用指定的 Worker URL: ${this.options.workerUrl}`);
|
|
15870
15701
|
}
|
|
15871
15702
|
}
|
|
15872
|
-
|
|
15873
|
-
|
|
15874
|
-
|
|
15875
|
-
destroyContext(this.screenshotContext);
|
|
15876
|
-
}
|
|
15877
|
-
catch (e) {
|
|
15878
|
-
// 忽略清理错误
|
|
15703
|
+
else {
|
|
15704
|
+
if (!this.options.silentMode) {
|
|
15705
|
+
console.log('📸 Worker URL 未指定,modern-screenshot 将自动处理');
|
|
15879
15706
|
}
|
|
15880
|
-
this.screenshotContext = null;
|
|
15881
15707
|
}
|
|
15882
|
-
|
|
15883
|
-
|
|
15884
|
-
|
|
15885
|
-
|
|
15886
|
-
const percent = Math.round((current / total) * 100);
|
|
15887
|
-
if (percent % 25 === 0 || current === total) { // 每 25% 或完成时打印
|
|
15888
|
-
console.log(`📸 截图进度: ${current}/${total} (${percent}%)`);
|
|
15889
|
-
}
|
|
15890
|
-
}
|
|
15891
|
-
};
|
|
15892
|
-
}
|
|
15893
|
-
// 添加重试机制创建新 context
|
|
15894
|
-
let retries = 0;
|
|
15895
|
-
const maxRetries = this.options.maxRetries || 2;
|
|
15896
|
-
while (retries <= maxRetries) {
|
|
15897
|
-
try {
|
|
15898
|
-
// 等待图片加载完成(确保内容是最新的)
|
|
15899
|
-
await this.waitForImagesToLoad(element);
|
|
15900
|
-
// 等待 DOM 更新完成(确保内容渲染完成)
|
|
15901
|
-
// 使用双重 requestAnimationFrame + setTimeout 确保内容完全渲染
|
|
15902
|
-
await new Promise(resolve => {
|
|
15903
|
-
requestAnimationFrame(() => {
|
|
15904
|
-
requestAnimationFrame(() => {
|
|
15905
|
-
// 根据截图间隔调整等待时间:频繁截图时等待更久
|
|
15906
|
-
const waitTime = this.options.interval < 2000 ? 200 : 100;
|
|
15907
|
-
setTimeout(resolve, waitTime);
|
|
15908
|
-
});
|
|
15909
|
-
});
|
|
15910
|
-
});
|
|
15911
|
-
// 创建 context 前,再次检查内容是否变化(防止在等待期间内容又变化了)
|
|
15912
|
-
const latestContentHash = this.calculateContentHash(element);
|
|
15913
|
-
if (latestContentHash !== contentHash) {
|
|
15914
|
-
if (!this.options.silentMode) {
|
|
15915
|
-
console.log('📸 等待期间内容发生变化,更新内容哈希');
|
|
15916
|
-
}
|
|
15917
|
-
// 更新 contentHash,但继续使用新的 context
|
|
15918
|
-
// 这样下次截图时会检测到变化
|
|
15919
|
-
}
|
|
15920
|
-
this.screenshotContext = await createContext$1(element, contextOptions);
|
|
15921
|
-
this.contextElement = element;
|
|
15922
|
-
this.contextOptionsHash = contextOptionsHash;
|
|
15923
|
-
this.contextContentHash = contentHash;
|
|
15924
|
-
this.contextLastUpdateTime = now;
|
|
15925
|
-
break;
|
|
15926
|
-
}
|
|
15927
|
-
catch (error) {
|
|
15928
|
-
if (retries === maxRetries) {
|
|
15929
|
-
throw new Error(`创建截图上下文失败(已重试 ${maxRetries} 次): ${error instanceof Error ? error.message : String(error)}`);
|
|
15930
|
-
}
|
|
15931
|
-
retries++;
|
|
15932
|
-
const delay = 1000 * retries; // 递增延迟:1秒、2秒...
|
|
15933
|
-
if (!this.options.silentMode) {
|
|
15934
|
-
console.warn(`📸 ⚠️ 创建截图上下文失败,${delay}ms 后重试 (${retries}/${maxRetries})...`);
|
|
15935
|
-
}
|
|
15936
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
15708
|
+
try {
|
|
15709
|
+
this.screenshotContext = await createContext$1(element, simpleContextOptions);
|
|
15710
|
+
if (!this.options.silentMode) {
|
|
15711
|
+
console.log('📸 Worker 上下文创建成功');
|
|
15937
15712
|
}
|
|
15938
15713
|
}
|
|
15939
|
-
|
|
15940
|
-
else {
|
|
15941
|
-
if (!this.options.silentMode) {
|
|
15942
|
-
console.log('📸 复用现有 context(性能优化)');
|
|
15943
|
-
}
|
|
15944
|
-
// ⚠️ 重要:modern-screenshot 的 context 在创建时会"快照" DOM 状态
|
|
15945
|
-
// 如果 DOM 内容在 context 创建后发生了变化,复用 context 会捕获到旧内容
|
|
15946
|
-
// 因此,我们需要在每次截图前再次检查内容是否变化
|
|
15947
|
-
// 再次计算内容哈希,检查是否在复用期间内容又变化了
|
|
15948
|
-
const latestContentHash = this.calculateContentHash(element);
|
|
15949
|
-
if (latestContentHash !== this.contextContentHash) {
|
|
15950
|
-
// 内容在复用期间又变化了,必须重新创建 context
|
|
15714
|
+
catch (error) {
|
|
15951
15715
|
if (!this.options.silentMode) {
|
|
15952
|
-
console.
|
|
15953
|
-
}
|
|
15954
|
-
// 销毁旧 context
|
|
15955
|
-
if (this.screenshotContext) {
|
|
15956
|
-
try {
|
|
15957
|
-
destroyContext(this.screenshotContext);
|
|
15958
|
-
}
|
|
15959
|
-
catch (e) {
|
|
15960
|
-
// 忽略清理错误
|
|
15961
|
-
}
|
|
15962
|
-
this.screenshotContext = null;
|
|
15716
|
+
console.error('📸 创建 Worker 上下文失败:', error);
|
|
15963
15717
|
}
|
|
15964
|
-
|
|
15965
|
-
await this.waitForImagesToLoad(element);
|
|
15966
|
-
await new Promise(resolve => {
|
|
15967
|
-
requestAnimationFrame(() => {
|
|
15968
|
-
requestAnimationFrame(() => {
|
|
15969
|
-
const waitTime = this.options.interval < 2000 ? 200 : 100;
|
|
15970
|
-
setTimeout(resolve, waitTime);
|
|
15971
|
-
});
|
|
15972
|
-
});
|
|
15973
|
-
});
|
|
15974
|
-
// 重新创建 context
|
|
15975
|
-
let retries = 0;
|
|
15976
|
-
const maxRetries = this.options.maxRetries || 2;
|
|
15977
|
-
while (retries <= maxRetries) {
|
|
15978
|
-
try {
|
|
15979
|
-
this.screenshotContext = await createContext$1(element, contextOptions);
|
|
15980
|
-
this.contextElement = element;
|
|
15981
|
-
this.contextOptionsHash = contextOptionsHash;
|
|
15982
|
-
this.contextContentHash = latestContentHash;
|
|
15983
|
-
this.contextLastUpdateTime = Date.now();
|
|
15984
|
-
break;
|
|
15985
|
-
}
|
|
15986
|
-
catch (error) {
|
|
15987
|
-
if (retries === maxRetries) {
|
|
15988
|
-
throw new Error(`重新创建截图上下文失败(已重试 ${maxRetries} 次): ${error instanceof Error ? error.message : String(error)}`);
|
|
15989
|
-
}
|
|
15990
|
-
retries++;
|
|
15991
|
-
const delay = 1000 * retries;
|
|
15992
|
-
if (!this.options.silentMode) {
|
|
15993
|
-
console.warn(`📸 ⚠️ 重新创建截图上下文失败,${delay}ms 后重试 (${retries}/${maxRetries})...`);
|
|
15994
|
-
}
|
|
15995
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
15996
|
-
}
|
|
15997
|
-
}
|
|
15998
|
-
}
|
|
15999
|
-
else {
|
|
16000
|
-
// 内容没有变化,可以安全复用 context
|
|
16001
|
-
// 但还是要等待图片加载完成,确保内容是最新的
|
|
16002
|
-
await this.waitForImagesToLoad(element);
|
|
16003
|
-
// 等待 DOM 更新完成
|
|
16004
|
-
await new Promise(resolve => {
|
|
16005
|
-
requestAnimationFrame(() => {
|
|
16006
|
-
requestAnimationFrame(() => {
|
|
16007
|
-
setTimeout(resolve, 100); // 额外等待 100ms,确保内容完全渲染
|
|
16008
|
-
});
|
|
16009
|
-
});
|
|
16010
|
-
});
|
|
15718
|
+
throw error;
|
|
16011
15719
|
}
|
|
16012
15720
|
}
|
|
16013
15721
|
try {
|
|
16014
|
-
//
|
|
16015
|
-
// 注意:timeout 已经在 createContext 时设置,modern-screenshot 内部会处理超时
|
|
15722
|
+
// 按照 demo 的方式:使用 domToWebp 时传递配置参数
|
|
16016
15723
|
let dataUrl;
|
|
16017
15724
|
const outputFormat = this.options.outputFormat || 'webp';
|
|
16018
15725
|
if (!this.options.silentMode) {
|
|
16019
15726
|
console.log(`📸 使用 ${outputFormat.toUpperCase()} 格式截图(直接输出,无需转换)...`);
|
|
16020
15727
|
}
|
|
15728
|
+
// 构建 domToWebp/domToJpeg/domToPng 的配置参数(和 demo 一致)
|
|
15729
|
+
const screenshotOptions = {
|
|
15730
|
+
scale: this.options.scale ?? 0.7, // 使用外部参数,默认 0.7(和 demo 一致)
|
|
15731
|
+
backgroundColor: this.options.backgroundColor ?? '#ffffff', // 默认白色背景
|
|
15732
|
+
type: `image/${outputFormat}`, // 使用配置的输出格式
|
|
15733
|
+
quality: this.options.quality ?? 0.6, // 使用外部参数,默认 0.6(和 demo 一致)
|
|
15734
|
+
drawImageInterval: this.options.drawImageInterval ?? 20, // 默认 20ms(和 demo 一致)
|
|
15735
|
+
features: {
|
|
15736
|
+
copyScrollbar: false,
|
|
15737
|
+
removeAbnormalAttributes: true,
|
|
15738
|
+
removeControlCharacter: true,
|
|
15739
|
+
fixSvgXmlDecode: true,
|
|
15740
|
+
restoreScrollPosition: false,
|
|
15741
|
+
},
|
|
15742
|
+
timeout: 10000, // 10秒超时(和 demo 一致)
|
|
15743
|
+
};
|
|
16021
15744
|
// 尝试使用 Worker 模式(context)
|
|
16022
15745
|
try {
|
|
16023
|
-
// 根据输出格式选择对应的 API
|
|
16024
|
-
// modern-screenshot 内部已经处理了超时,不需要额外的 Promise.race
|
|
15746
|
+
// 根据输出格式选择对应的 API,传递配置参数(和 demo 一致)
|
|
16025
15747
|
if (outputFormat === 'webp') {
|
|
16026
|
-
|
|
16027
|
-
dataUrl = await domToWebp(this.screenshotContext);
|
|
15748
|
+
dataUrl = await domToWebp(this.screenshotContext, screenshotOptions);
|
|
16028
15749
|
}
|
|
16029
15750
|
else if (outputFormat === 'jpeg') {
|
|
16030
|
-
|
|
16031
|
-
dataUrl = await domToJpeg(this.screenshotContext);
|
|
15751
|
+
dataUrl = await domToJpeg(this.screenshotContext, screenshotOptions);
|
|
16032
15752
|
}
|
|
16033
15753
|
else {
|
|
16034
|
-
|
|
16035
|
-
dataUrl = await domToPng(this.screenshotContext);
|
|
15754
|
+
dataUrl = await domToPng(this.screenshotContext, screenshotOptions);
|
|
16036
15755
|
}
|
|
16037
15756
|
// 验证截图结果
|
|
16038
15757
|
if (!dataUrl || dataUrl.length < 100) {
|
|
@@ -16044,7 +15763,7 @@ class ScreenshotManager {
|
|
|
16044
15763
|
return dataUrl;
|
|
16045
15764
|
}
|
|
16046
15765
|
catch (workerError) {
|
|
16047
|
-
// Worker
|
|
15766
|
+
// Worker 模式失败,回退到普通模式(和 demo 一致)
|
|
16048
15767
|
if (!this.options.silentMode) {
|
|
16049
15768
|
console.warn('📸 Worker 模式失败,回退到普通模式:', workerError);
|
|
16050
15769
|
}
|
|
@@ -16058,14 +15777,14 @@ class ScreenshotManager {
|
|
|
16058
15777
|
}
|
|
16059
15778
|
this.screenshotContext = null;
|
|
16060
15779
|
}
|
|
16061
|
-
// 回退到普通模式(直接使用
|
|
16062
|
-
//
|
|
15780
|
+
// 回退到普通模式(直接使用 element,不传 context)
|
|
15781
|
+
// 使用更低的参数(和 demo 一致)
|
|
16063
15782
|
const fallbackOptions = {
|
|
16064
|
-
scale:
|
|
16065
|
-
backgroundColor: '#ffffff',
|
|
16066
|
-
type: `image/${outputFormat}`,
|
|
16067
|
-
quality:
|
|
16068
|
-
drawImageInterval: 20,
|
|
15783
|
+
scale: 0.3, // 回退模式使用更低的 scale(和 demo 一致)
|
|
15784
|
+
backgroundColor: this.options.backgroundColor ?? '#ffffff',
|
|
15785
|
+
type: `image/${outputFormat}`,
|
|
15786
|
+
quality: 0.3, // 回退模式使用更低的质量(和 demo 一致)
|
|
15787
|
+
drawImageInterval: this.options.drawImageInterval ?? 20,
|
|
16069
15788
|
features: {
|
|
16070
15789
|
copyScrollbar: false,
|
|
16071
15790
|
removeAbnormalAttributes: true,
|
|
@@ -16073,10 +15792,8 @@ class ScreenshotManager {
|
|
|
16073
15792
|
fixSvgXmlDecode: true,
|
|
16074
15793
|
restoreScrollPosition: false,
|
|
16075
15794
|
},
|
|
16076
|
-
timeout:
|
|
15795
|
+
timeout: 10000, // 10秒超时(和 demo 一致)
|
|
16077
15796
|
};
|
|
16078
|
-
// 限制 timeout 最多 15 秒
|
|
16079
|
-
fallbackOptions.timeout = Math.min(fallbackOptions.timeout, 15000);
|
|
16080
15797
|
if (outputFormat === 'webp') {
|
|
16081
15798
|
dataUrl = await domToWebp(element, fallbackOptions);
|
|
16082
15799
|
}
|
|
@@ -17423,10 +17140,6 @@ class ScreenshotManager {
|
|
|
17423
17140
|
// 忽略清理错误
|
|
17424
17141
|
}
|
|
17425
17142
|
this.screenshotContext = null;
|
|
17426
|
-
this.contextElement = null;
|
|
17427
|
-
this.contextOptionsHash = '';
|
|
17428
|
-
this.contextContentHash = '';
|
|
17429
|
-
this.contextLastUpdateTime = 0;
|
|
17430
17143
|
}
|
|
17431
17144
|
if (!this.options.silentMode) {
|
|
17432
17145
|
console.log(`📸 截图引擎已更新: ${oldEngine} → ${newEngine}`);
|
|
@@ -17450,10 +17163,6 @@ class ScreenshotManager {
|
|
|
17450
17163
|
// 忽略清理错误
|
|
17451
17164
|
}
|
|
17452
17165
|
this.screenshotContext = null;
|
|
17453
|
-
this.contextElement = null;
|
|
17454
|
-
this.contextOptionsHash = '';
|
|
17455
|
-
this.contextContentHash = '';
|
|
17456
|
-
this.contextLastUpdateTime = 0;
|
|
17457
17166
|
}
|
|
17458
17167
|
this.stopScreenshot();
|
|
17459
17168
|
if (this.worker) {
|