fix: 优化叠加图层级关系与选中失焦逻辑

This commit is contained in:
Zhukj
2026-04-17 14:29:03 +08:00
parent 8255a1c426
commit 56e5aad22f
4 changed files with 70 additions and 13 deletions

View File

@@ -53,7 +53,7 @@
13. 顶部工具栏下方16px的位置,固定放置文本编辑器工具栏,加粗,斜体,字体颜色,字体,字号,可编辑文字样式
14. 字号逻辑调整,输入框字号只在自身原本字号上增减
15. 文本输入框添加辅助线,完善辅助线的吸附逻辑更加精准,辅助线颜色为红色
16.
16. 顶部工具栏新增层叠图,可添加多张层叠图,单击选中状态可缩放删除自由移动位置,置于背景图之上,输入框与层叠图点击只能同时选中一个

View File

@@ -222,14 +222,15 @@ html, body {
overflow: hidden;
}
/* 层叠图层 - 位于背景图之上、文字之下 */
/* 层叠图层 - 位于背景图之上、文字之下、提示文字之上 */
.overlay-layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
pointer-events: auto;
z-index: 6;
}
.overlay-layer .overlay-image {
@@ -282,11 +283,13 @@ html, body {
width: 100%;
height: 100%;
pointer-events: none;
z-index: 7;
}
/* 输入框可交互 */
.preview-input-layer .text-input {
pointer-events: auto;
z-index: 8;
}
/* 背景图 - 保持比例,可滑动调整位置 */

View File

@@ -48,8 +48,6 @@
<!-- 图片展示区 -->
<div class="canvas-area" id="canvasArea">
<div class="preview image-container empty" id="imageContainer">
<!-- 提示文字移到预览白板中 -->
<div class="empty-tip" id="emptyTip">请点击上方「添加图片」按钮上传背景图</div>
<!-- 背景图层 -->
<div class="preview-bg-layer" id="bgLayer">
<img id="bgImage" src="" alt="背景图">
@@ -66,6 +64,8 @@
<!-- 文字输入框2 - 右下角 -->
<div class="text-input" id="input2" contenteditable="false" style="left: 5%; top: 90%;">编号:</div>
</div>
<!-- 提示文字(最上层,层叠图之下) -->
<div class="empty-tip" id="emptyTip">请点击上方「添加图片」按钮上传背景图</div>
</div>
</div>

View File

@@ -405,23 +405,29 @@
});
}
// 选中层叠图
// 选中层叠图(同时取消输入框选中)
let selectedOverlay = null;
function selectOverlay(overlayEl) {
if (selectedOverlay) {
if (selectedInput) {
selectedInput.classList.remove('selected');
selectedInput = null;
}
if (editingInput) {
endEdit(editingInput);
}
if (selectedOverlay && selectedOverlay !== overlayEl) {
selectedOverlay.classList.remove('selected');
}
selectedOverlay = overlayEl;
overlayEl.classList.add('selected');
}
// 点击背景取消选中层叠图
// 点击背景/空白处取消选中层叠图
imageContainer.addEventListener('click', (e) => {
if (e.target === imageContainer ||
e.target === bgLayer ||
e.target === bgImage ||
e.target === emptyTip ||
e.target.closest('.preview-bg-layer')) {
const isOverlayImage = e.target.closest('.overlay-image');
const isTextInput = e.target.closest('.text-input');
if (!isOverlayImage && !isTextInput) {
if (selectedOverlay) {
selectedOverlay.classList.remove('selected');
selectedOverlay = null;
@@ -732,6 +738,10 @@
// 选中输入框
function selectInput(element) {
if (selectedOverlay) {
selectedOverlay.classList.remove('selected');
selectedOverlay = null;
}
if (editingInput && editingInput !== element) {
endEdit(editingInput);
}
@@ -1404,6 +1414,9 @@
drawImageWithOffset(ctx, currentImage, containerWidth, containerHeight);
}
// 绘制层叠图(等待图片加载完成)
await drawOverlayImages(ctx);
// 绘制文字
drawTextOnCanvas(ctx, input1);
drawTextOnCanvas(ctx, input2);
@@ -1411,6 +1424,47 @@
return canvas;
}
// 绘制层叠图
function drawOverlayImages(ctx) {
return new Promise((resolve) => {
const overlayImages = overlayLayer.querySelectorAll('.overlay-image');
if (overlayImages.length === 0) {
resolve();
return;
}
let loadedCount = 0;
overlayImages.forEach(overlayEl => {
const imgEl = overlayEl.querySelector('img');
if (!imgEl) {
loadedCount++;
return;
}
const left = overlayEl.offsetLeft;
const top = overlayEl.offsetTop;
const width = overlayEl.offsetWidth;
const height = overlayEl.offsetHeight;
const img = new Image();
img.onload = () => {
ctx.drawImage(img, left, top, width, height);
loadedCount++;
if (loadedCount >= overlayImages.length) {
resolve();
}
};
img.onerror = () => {
loadedCount++;
if (loadedCount >= overlayImages.length) {
resolve();
}
};
img.src = imgEl.src;
});
});
}
// 绘制图片(考虑滑动偏移)
function drawImageWithOffset(ctx, img, containerWidth, containerHeight) {
const imgRatio = img.naturalWidth / img.naturalHeight;