@koi-br/ocr-web-sdk 1.0.36 → 1.0.38
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/{index-BBpVx1t-.js → index-BrQWl5nv.js} +84 -84
- package/dist/{index-BK8otfpE.mjs → index-Ck53H0Dd.mjs} +7664 -7629
- package/dist/index.cjs.js +2 -2
- package/dist/index.esm.js +2 -2
- package/dist/{tiff.min-WauPM8ew.mjs → tiff.min-BOpS7e2e.mjs} +1 -1
- package/dist/{tiff.min-DstYahTd.js → tiff.min-BYCiqS9a.js} +1 -1
- package/package.json +1 -1
- package/preview/ImagePreview.vue +147 -3
package/package.json
CHANGED
package/preview/ImagePreview.vue
CHANGED
|
@@ -116,7 +116,17 @@
|
|
|
116
116
|
@mouseleave="stopPan"
|
|
117
117
|
@scroll="handleScroll"
|
|
118
118
|
>
|
|
119
|
-
|
|
119
|
+
<!-- 自适应宽度计算 Loading -->
|
|
120
|
+
<div v-if="isCalculatingAutoFit && autoFitWidth" class="auto-fit-loading">
|
|
121
|
+
<div class="loading-spinner"></div>
|
|
122
|
+
<div class="loading-text">加载中...</div>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<div
|
|
126
|
+
class="image-wrapper-container"
|
|
127
|
+
:style="containerStyle"
|
|
128
|
+
:class="{ 'image-hidden': !isImageReady && autoFitWidth }"
|
|
129
|
+
>
|
|
120
130
|
<!-- 渲染所有图片页面 -->
|
|
121
131
|
<div
|
|
122
132
|
v-for="(imageUrl, pageIndex) in imageUrls"
|
|
@@ -390,6 +400,24 @@ const position = ref({ x: 0, y: 0 });
|
|
|
390
400
|
const isPanning = ref(false);
|
|
391
401
|
const lastPosition = ref({ x: 0, y: 0 });
|
|
392
402
|
const initialAutoFitScale = ref<number | null>(null); // 记录初始自适应缩放比例
|
|
403
|
+
const isCalculatingAutoFit = ref(false); // 标记是否正在计算自适应宽度(显示 loading)
|
|
404
|
+
const isImageReady = ref(false); // 标记图片是否已准备好显示(自适应宽度计算完成)
|
|
405
|
+
|
|
406
|
+
// 监听图片URL变化,当有新图片时立即隐藏(等待自适应宽度计算)
|
|
407
|
+
watch(
|
|
408
|
+
() => imageUrls.value,
|
|
409
|
+
(newUrls, oldUrls) => {
|
|
410
|
+
// 如果有新的图片URL,且启用自适应宽度,立即隐藏图片
|
|
411
|
+
if (newUrls && newUrls.length > 0 && props.autoFitWidth) {
|
|
412
|
+
isImageReady.value = false;
|
|
413
|
+
isCalculatingAutoFit.value = true;
|
|
414
|
+
} else if (!props.autoFitWidth) {
|
|
415
|
+
// 如果没有启用自适应宽度,立即显示
|
|
416
|
+
isImageReady.value = true;
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
{ immediate: true }
|
|
420
|
+
);
|
|
393
421
|
const isUserZooming = ref(false); // 标记用户是否主动缩放
|
|
394
422
|
|
|
395
423
|
// 滚动翻页相关
|
|
@@ -841,10 +869,18 @@ const switchToPage = (page: number) => {
|
|
|
841
869
|
`[data-page-number="${page}"]`
|
|
842
870
|
) as HTMLElement;
|
|
843
871
|
if (pageElement) {
|
|
872
|
+
// 标记这是翻页滚动,不应该被同步滚动干扰
|
|
873
|
+
containerRef.value.dataset.pageScrolling = 'true';
|
|
844
874
|
pageElement.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
845
875
|
// 更新 lastScrollTop,确保滚动方向判断准确
|
|
846
876
|
nextTick(() => {
|
|
847
877
|
lastScrollTop = containerRef.value?.scrollTop || 0;
|
|
878
|
+
// 延迟清除标记,确保滚动完成
|
|
879
|
+
setTimeout(() => {
|
|
880
|
+
if (containerRef.value) {
|
|
881
|
+
delete containerRef.value.dataset.pageScrolling;
|
|
882
|
+
}
|
|
883
|
+
}, 500); // scrollIntoView 的 smooth 动画通常需要 300-500ms
|
|
848
884
|
});
|
|
849
885
|
}
|
|
850
886
|
}
|
|
@@ -930,6 +966,10 @@ const onImageLoad = (event: Event, pageNum: number) => {
|
|
|
930
966
|
if (pageNum === 1 && props.autoFitWidth) {
|
|
931
967
|
// 重置用户缩放标记
|
|
932
968
|
isUserZooming.value = false;
|
|
969
|
+
|
|
970
|
+
// 隐藏图片,显示 loading
|
|
971
|
+
isImageReady.value = false;
|
|
972
|
+
isCalculatingAutoFit.value = true;
|
|
933
973
|
|
|
934
974
|
// 使用双重 nextTick 确保容器尺寸已确定
|
|
935
975
|
nextTick(() => {
|
|
@@ -941,9 +981,18 @@ const onImageLoad = (event: Event, pageNum: number) => {
|
|
|
941
981
|
scale.value = autoScale;
|
|
942
982
|
initialAutoFitScale.value = autoScale; // 记录初始自适应缩放比例
|
|
943
983
|
}
|
|
984
|
+
// 计算完成后,显示图片并隐藏 loading
|
|
985
|
+
isCalculatingAutoFit.value = false;
|
|
986
|
+
// 使用 requestAnimationFrame 确保在下一帧显示,避免闪烁
|
|
987
|
+
requestAnimationFrame(() => {
|
|
988
|
+
isImageReady.value = true;
|
|
989
|
+
});
|
|
944
990
|
}, 100); // 增加延迟,确保所有图片都已加载
|
|
945
991
|
});
|
|
946
992
|
});
|
|
993
|
+
} else if (!props.autoFitWidth) {
|
|
994
|
+
// 如果没有启用自适应宽度,立即显示图片
|
|
995
|
+
isImageReady.value = true;
|
|
947
996
|
}
|
|
948
997
|
|
|
949
998
|
// 如果第一页已经加载完成,且当前页不是第一页,也应用自适应宽度
|
|
@@ -1840,6 +1889,33 @@ const saveAnnotation = () => {
|
|
|
1840
1889
|
* 处理滚动事件(隐藏批注按钮和文本块高亮,以及滚动翻页)
|
|
1841
1890
|
*/
|
|
1842
1891
|
const handleScroll = (e: Event) => {
|
|
1892
|
+
const container = e.target as HTMLElement;
|
|
1893
|
+
|
|
1894
|
+
// 检查是否是同步滚动触发的
|
|
1895
|
+
const isSyncing = container?.dataset?.syncingScroll === 'true';
|
|
1896
|
+
if (isSyncing) {
|
|
1897
|
+
// 即使是被同步滚动触发的,也应该立即更新页码(但不触发翻页动画)
|
|
1898
|
+
// 使用 requestAnimationFrame 确保在浏览器渲染后立即更新
|
|
1899
|
+
if (
|
|
1900
|
+
props.enableScrollPaging &&
|
|
1901
|
+
totalPages.value > 1 &&
|
|
1902
|
+
!isScrollPaging.value
|
|
1903
|
+
) {
|
|
1904
|
+
// 立即更新页码,不等待防抖
|
|
1905
|
+
requestAnimationFrame(() => {
|
|
1906
|
+
updateCurrentPageFromScroll();
|
|
1907
|
+
// 清除标记(在页码更新后)
|
|
1908
|
+
delete container.dataset.syncingScroll;
|
|
1909
|
+
});
|
|
1910
|
+
} else {
|
|
1911
|
+
// 如果没有启用滚动翻页,立即清除标记
|
|
1912
|
+
delete container.dataset.syncingScroll;
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
// 同步滚动时,不执行其他逻辑(如隐藏批注按钮等)
|
|
1916
|
+
return;
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1843
1919
|
if (hideTimer) {
|
|
1844
1920
|
clearTimeout(hideTimer);
|
|
1845
1921
|
}
|
|
@@ -1861,16 +1937,22 @@ const handleScroll = (e: Event) => {
|
|
|
1861
1937
|
scale.value = initialAutoFitScale.value;
|
|
1862
1938
|
}
|
|
1863
1939
|
|
|
1864
|
-
//
|
|
1940
|
+
// 滚动翻页功能(用户主动滚动时)
|
|
1865
1941
|
if (
|
|
1866
1942
|
props.enableScrollPaging &&
|
|
1867
1943
|
totalPages.value > 1 &&
|
|
1868
1944
|
!isScrollPaging.value
|
|
1869
1945
|
) {
|
|
1946
|
+
// 立即更新页码(使用 requestAnimationFrame 确保在渲染后更新)
|
|
1947
|
+
requestAnimationFrame(() => {
|
|
1948
|
+
updateCurrentPageFromScroll();
|
|
1949
|
+
});
|
|
1950
|
+
// 同时使用防抖处理其他逻辑(如事件触发)
|
|
1870
1951
|
handleScrollPaging(e);
|
|
1871
1952
|
}
|
|
1872
1953
|
};
|
|
1873
1954
|
|
|
1955
|
+
|
|
1874
1956
|
// 记录上次滚动位置,用于判断滚动方向
|
|
1875
1957
|
let lastScrollTop = 0;
|
|
1876
1958
|
|
|
@@ -1939,6 +2021,7 @@ const handleScrollPaging = (e: Event) => {
|
|
|
1939
2021
|
}
|
|
1940
2022
|
|
|
1941
2023
|
// 使用防抖,避免频繁触发
|
|
2024
|
+
// 减少延迟到50ms,提高响应速度
|
|
1942
2025
|
scrollPagingTimer = setTimeout(() => {
|
|
1943
2026
|
// 再次检查是否正在翻页
|
|
1944
2027
|
if (isScrollPaging.value) {
|
|
@@ -1947,7 +2030,7 @@ const handleScrollPaging = (e: Event) => {
|
|
|
1947
2030
|
|
|
1948
2031
|
// 更新当前页码(基于视口中心最近的页面)
|
|
1949
2032
|
updateCurrentPageFromScroll();
|
|
1950
|
-
},
|
|
2033
|
+
}, 50);
|
|
1951
2034
|
};
|
|
1952
2035
|
|
|
1953
2036
|
/**
|
|
@@ -2228,6 +2311,10 @@ const handleContainerResize = () => {
|
|
|
2228
2311
|
resizeTimer = null;
|
|
2229
2312
|
}
|
|
2230
2313
|
|
|
2314
|
+
// 隐藏图片,显示 loading
|
|
2315
|
+
isImageReady.value = false;
|
|
2316
|
+
isCalculatingAutoFit.value = true;
|
|
2317
|
+
|
|
2231
2318
|
// 立即计算并应用新的缩放比例,避免过渡期间露出底色
|
|
2232
2319
|
// 使用 requestAnimationFrame 确保在浏览器重绘前更新
|
|
2233
2320
|
requestAnimationFrame(() => {
|
|
@@ -2245,6 +2332,11 @@ const handleContainerResize = () => {
|
|
|
2245
2332
|
scale.value = finalScale;
|
|
2246
2333
|
initialAutoFitScale.value = finalScale;
|
|
2247
2334
|
}
|
|
2335
|
+
// 计算完成后,显示图片并隐藏 loading
|
|
2336
|
+
isCalculatingAutoFit.value = false;
|
|
2337
|
+
requestAnimationFrame(() => {
|
|
2338
|
+
isImageReady.value = true;
|
|
2339
|
+
});
|
|
2248
2340
|
}, 350); // 350ms 延迟,略大于过渡动画时间(300ms),确保过渡完成后稳定
|
|
2249
2341
|
});
|
|
2250
2342
|
};
|
|
@@ -2258,6 +2350,9 @@ onMounted(() => {
|
|
|
2258
2350
|
if (firstPageImage && firstPageImage.complete && props.autoFitWidth) {
|
|
2259
2351
|
const firstPageSize = imageSizes.get(1);
|
|
2260
2352
|
if (firstPageSize && firstPageSize.width > 0) {
|
|
2353
|
+
// 隐藏图片,显示 loading
|
|
2354
|
+
isImageReady.value = false;
|
|
2355
|
+
isCalculatingAutoFit.value = true;
|
|
2261
2356
|
nextTick(() => {
|
|
2262
2357
|
nextTick(() => {
|
|
2263
2358
|
setTimeout(() => {
|
|
@@ -2266,10 +2361,18 @@ onMounted(() => {
|
|
|
2266
2361
|
scale.value = autoScale;
|
|
2267
2362
|
initialAutoFitScale.value = autoScale;
|
|
2268
2363
|
}
|
|
2364
|
+
// 计算完成后,显示图片并隐藏 loading
|
|
2365
|
+
isCalculatingAutoFit.value = false;
|
|
2366
|
+
requestAnimationFrame(() => {
|
|
2367
|
+
isImageReady.value = true;
|
|
2368
|
+
});
|
|
2269
2369
|
}, 100);
|
|
2270
2370
|
});
|
|
2271
2371
|
});
|
|
2272
2372
|
}
|
|
2373
|
+
} else if (!props.autoFitWidth) {
|
|
2374
|
+
// 如果没有启用自适应宽度,立即显示图片
|
|
2375
|
+
isImageReady.value = true;
|
|
2273
2376
|
}
|
|
2274
2377
|
|
|
2275
2378
|
// 监听容器尺寸变化(用于响应外部收起/展开操作)
|
|
@@ -2339,6 +2442,47 @@ defineExpose({
|
|
|
2339
2442
|
overflow: auto;
|
|
2340
2443
|
}
|
|
2341
2444
|
|
|
2445
|
+
// 自适应宽度计算 Loading
|
|
2446
|
+
.auto-fit-loading {
|
|
2447
|
+
position: absolute;
|
|
2448
|
+
top: 50%;
|
|
2449
|
+
left: 50%;
|
|
2450
|
+
transform: translate(-50%, -50%);
|
|
2451
|
+
z-index: 1000;
|
|
2452
|
+
display: flex;
|
|
2453
|
+
flex-direction: column;
|
|
2454
|
+
align-items: center;
|
|
2455
|
+
gap: 12px;
|
|
2456
|
+
padding: 20px 30px;
|
|
2457
|
+
}
|
|
2458
|
+
|
|
2459
|
+
.loading-spinner {
|
|
2460
|
+
width: 32px;
|
|
2461
|
+
height: 32px;
|
|
2462
|
+
border: 3px solid #e5e7eb;
|
|
2463
|
+
border-top-color: #1890ff;
|
|
2464
|
+
border-radius: 50%;
|
|
2465
|
+
animation: spin 0.8s linear infinite;
|
|
2466
|
+
}
|
|
2467
|
+
|
|
2468
|
+
@keyframes spin {
|
|
2469
|
+
to {
|
|
2470
|
+
transform: rotate(360deg);
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2474
|
+
.loading-text {
|
|
2475
|
+
font-size: 14px;
|
|
2476
|
+
color: #666;
|
|
2477
|
+
white-space: nowrap;
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
// 图片隐藏状态(自适应宽度计算完成前)
|
|
2481
|
+
// 使用 display: none 确保图片完全不可见,不会在加载过程中显示
|
|
2482
|
+
.image-wrapper-container.image-hidden {
|
|
2483
|
+
display: none !important;
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2342
2486
|
// 页码信息样式
|
|
2343
2487
|
.page-info {
|
|
2344
2488
|
display: inline-flex;
|