Skip to content

Commit 7edbb81

Browse files
author
wenhuxian
committed
feat: 优化图片灯箱功能
- 改进拖动交互,修复拖动偏移问题 - 优化滚轮缩放功能和响应速度 - 重新设计控制按钮样式,移至底部居中 - 使用 GPU 加速优化性能 - 优化事件处理,使用 useCallback 提升性能
1 parent 23e1fef commit 7edbb81

File tree

2 files changed

+112
-31
lines changed

2 files changed

+112
-31
lines changed

src/renderer/App.tsx

Lines changed: 64 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,26 @@ const App: React.FC = () => {
732732
const [isDragging, setIsDragging] = useState(false);
733733
const [dragStart, setDragStart] = useState({ x: 0, y: 0 });
734734

735+
// Lightbox control handlers - memoized for performance
736+
const handleLightboxShrink = useCallback(() => {
737+
setLightboxScale(s => Math.max(0.25, s - 0.25));
738+
}, []);
739+
740+
const handleLightboxReset = useCallback(() => {
741+
setLightboxScale(1);
742+
setLightboxOffset({ x: 0, y: 0 });
743+
}, []);
744+
745+
const handleLightboxEnlarge = useCallback(() => {
746+
setLightboxScale(s => Math.min(4, s + 0.25));
747+
}, []);
748+
749+
const handleLightboxClose = useCallback(() => {
750+
setLightboxImage(null);
751+
setLightboxOffset({ x: 0, y: 0 });
752+
setLightboxScale(1);
753+
}, []);
754+
735755
// Calculate actual list width from ratio (Moved up)
736756

737757

@@ -1099,7 +1119,7 @@ const App: React.FC = () => {
10991119
}
11001120
}, [selectedIssue]);
11011121

1102-
// Lightbox keyboard and wheel handlers
1122+
// Lightbox keyboard handlers
11031123
useEffect(() => {
11041124
if (!lightboxImage) return;
11051125

@@ -1127,21 +1147,10 @@ const App: React.FC = () => {
11271147
}
11281148
};
11291149

1130-
const handleWheel = (e: WheelEvent) => {
1131-
e.preventDefault();
1132-
if (e.deltaY < 0) {
1133-
setLightboxScale(s => Math.min(4, s + 0.1));
1134-
} else {
1135-
setLightboxScale(s => Math.max(0.25, s - 0.1));
1136-
}
1137-
};
1138-
11391150
window.addEventListener('keydown', handleKeyDown);
1140-
window.addEventListener('wheel', handleWheel, { passive: false });
11411151

11421152
return () => {
11431153
window.removeEventListener('keydown', handleKeyDown);
1144-
window.removeEventListener('wheel', handleWheel);
11451154
};
11461155
}, [lightboxImage]);
11471156

@@ -2564,37 +2573,61 @@ const App: React.FC = () => {
25642573
{/* Modals & Overlays */}
25652574
{
25662575
lightboxImage && (
2567-
<div className="image-lightbox-overlay" onClick={() => { setLightboxImage(null); setLightboxOffset({ x: 0, y: 0 }); setLightboxScale(1); }}
2576+
<div
2577+
className="image-lightbox-overlay"
2578+
onClick={handleLightboxClose}
2579+
onWheel={(e) => {
2580+
e.preventDefault();
2581+
const delta = e.deltaY;
2582+
if (delta < 0) {
2583+
setLightboxScale(s => Math.min(4, s + 0.1));
2584+
} else {
2585+
setLightboxScale(s => Math.max(0.25, s - 0.1));
2586+
}
2587+
}}
25682588
onMouseMove={(e) => {
25692589
if (isDragging) {
2570-
setLightboxOffset(o => ({
2571-
x: o.x + e.movementX,
2572-
y: o.y + e.movementY
2573-
}));
2590+
setLightboxOffset({
2591+
x: e.clientX - dragStart.x,
2592+
y: e.clientY - dragStart.y
2593+
});
25742594
}
25752595
}}
25762596
onMouseUp={() => setIsDragging(false)}
25772597
onMouseLeave={() => setIsDragging(false)}
25782598
>
2579-
<AuthenticatedImage
2580-
src={lightboxImage}
2581-
alt="Enlarged"
2582-
fetchBlob={(u) => vm.fetchImageBlob(u)}
2583-
className="image-lightbox-content"
2599+
<div
2600+
onClick={(e) => e.stopPropagation()}
2601+
onMouseDown={(e) => {
2602+
e.preventDefault();
2603+
e.stopPropagation();
2604+
setIsDragging(true);
2605+
setDragStart({ x: e.clientX - lightboxOffset.x, y: e.clientY - lightboxOffset.y });
2606+
}}
25842607
style={{
2585-
transform: `translate(${lightboxOffset.x}px, ${lightboxOffset.y}px) scale(${lightboxScale})`,
25862608
cursor: isDragging ? 'grabbing' : 'grab',
25872609
userSelect: 'none',
2588-
pointerEvents: 'auto'
2610+
display: 'inline-block',
2611+
transform: `translate(${lightboxOffset.x}px, ${lightboxOffset.y}px) scale(${lightboxScale})`,
2612+
transformOrigin: 'center center'
25892613
}}
2590-
onClick={(e) => e.stopPropagation()}
2591-
onMouseDown={(e) => { e.preventDefault(); e.stopPropagation(); setIsDragging(true); }}
2592-
/>
2614+
>
2615+
<AuthenticatedImage
2616+
src={lightboxImage}
2617+
alt="Enlarged"
2618+
fetchBlob={(u) => vm.fetchImageBlob(u)}
2619+
className="image-lightbox-content"
2620+
style={{
2621+
pointerEvents: 'none',
2622+
display: 'block'
2623+
}}
2624+
/>
2625+
</div>
25932626
<div className="image-lightbox-controls" onClick={e => e.stopPropagation()}>
2594-
<button onClick={() => setLightboxScale(s => Math.max(0.25, s - 0.25))}></button>
2595-
<button onClick={() => { setLightboxScale(1); setLightboxOffset({ x: 0, y: 0 }); }}>重置</button>
2596-
<button onClick={() => setLightboxScale(s => Math.min(4, s + 0.25))}></button>
2597-
<button onClick={() => { setLightboxImage(null); setLightboxOffset({ x: 0, y: 0 }); setLightboxScale(1); }}></button>
2627+
<button onClick={handleLightboxShrink}></button>
2628+
<button onClick={handleLightboxReset}></button>
2629+
<button onClick={handleLightboxEnlarge}>+</button>
2630+
<button onClick={handleLightboxClose}></button>
25982631
</div>
25992632
</div>
26002633
)

src/renderer/index.css

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,8 @@ body {
431431
align-items: center;
432432
justify-content: center;
433433
z-index: 10000;
434+
will-change: opacity;
435+
transform: translateZ(0);
434436
}
435437

436438
.image-lightbox-content {
@@ -439,6 +441,52 @@ body {
439441
object-fit: contain;
440442
box-shadow: 0 40px 100px rgba(0, 0, 0, 0.8), 0 0 0 1px rgba(255, 255, 255, 0.1);
441443
border-radius: 12px;
444+
will-change: transform;
445+
transform: translateZ(0);
446+
}
447+
448+
.image-lightbox-controls {
449+
position: fixed;
450+
bottom: 40px;
451+
left: 50%;
452+
transform: translateX(-50%) translateZ(0);
453+
display: flex;
454+
gap: 12px;
455+
padding: 12px 20px;
456+
background: rgba(0, 0, 0, 0.9);
457+
border-radius: 16px;
458+
border: 1px solid rgba(255, 255, 255, 0.1);
459+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
460+
z-index: 10001;
461+
will-change: transform;
462+
}
463+
464+
.image-lightbox-controls button {
465+
background: rgba(255, 255, 255, 0.1);
466+
border: 1px solid rgba(255, 255, 255, 0.15);
467+
color: #ffffff !important;
468+
padding: 10px 16px;
469+
border-radius: 10px;
470+
cursor: pointer;
471+
font-size: 16px;
472+
font-weight: 500;
473+
min-width: 60px;
474+
display: flex;
475+
align-items: center;
476+
justify-content: center;
477+
white-space: nowrap;
478+
pointer-events: auto;
479+
will-change: background-color, border-color;
480+
}
481+
482+
.image-lightbox-controls button:hover {
483+
background: rgba(255, 255, 255, 0.25);
484+
border-color: rgba(255, 255, 255, 0.4);
485+
}
486+
487+
.image-lightbox-controls button:active {
488+
background: rgba(255, 255, 255, 0.3);
489+
border-color: rgba(255, 255, 255, 0.5);
442490
}
443491

444492
@keyframes spin {

0 commit comments

Comments
 (0)