feat(图层管理): 为二维码添加图层支持并实现相关功能

- 在状态管理中新增 qrCounter 用于生成唯一图层 ID
- 为二维码元素添加 dataset.layerId 属性
- 实现二维码图层更新事件机制
- 在图层列表中显示二维码元素并支持选中操作
- 完善二维码的绘制逻辑,支持透明度设置
This commit is contained in:
Zhukj
2026-04-27 08:46:49 +08:00
parent 4ee95df792
commit 6a0294f0c0
2 changed files with 91 additions and 7 deletions

View File

@@ -2436,6 +2436,11 @@
if (!layersBtn || !layersPanel) return;
// 监听二维码图层更新事件
document.addEventListener('updateLayers', () => {
updateLayersList();
});
// 打开/关闭图层面板(同时支持桌面和移动端)
const toggleLayersPanel = () => {
layersPanel.classList.toggle('active');
@@ -2590,7 +2595,20 @@
}
});
// 4. 层叠图(最上层)
// 4. 二维码
const qrItems = document.querySelectorAll('.qr-item');
qrItems.forEach((qr, index) => {
layers.push({
id: qr.dataset.layerId || `qr_${index}`,
element: qr,
name: `二维码 ${index + 1}`,
type: 'qrcode',
icon: '🔲',
visible: !qr.classList.contains('layer-hidden')
});
});
// 5. 层叠图(最上层)
const overlayImages = overlayLayer.querySelectorAll('.overlay-image');
overlayImages.forEach((overlay, index) => {
layers.push({
@@ -2660,7 +2678,8 @@
const names = {
'text': '文本',
'overlay': '层叠图',
'background': '背景图'
'background': '背景图',
'qrcode': '二维码'
};
return names[type] || type;
}
@@ -2687,6 +2706,40 @@
selectInput(element);
} else if (element.classList.contains('overlay-image')) {
selectOverlay(element);
} else if (element.classList.contains('qr-item')) {
// 选中二维码
if (window.QRCodeAPI) {
window.QRCodeAPI.hideTools();
}
// 取消其他选中
document.querySelectorAll('.qr-item').forEach(el => {
el.classList.remove('qr-selected');
});
// 选中当前二维码
element.classList.add('qr-selected');
// 显示二维码工具栏
editorToolbar.classList.add('active');
textTools.classList.remove('active');
imageTools.classList.remove('active');
bgTools.classList.remove('active');
const qrTools = document.getElementById('qrTools');
if (qrTools) qrTools.classList.add('active');
// 同步工具栏值
const qrImg = element.querySelector('img');
const qrOpacitySlider = document.getElementById('qrOpacitySlider');
const qrOpacityValue = document.getElementById('qrOpacityValue');
const qrScaleSlider = document.getElementById('qrScaleSlider');
const qrScaleValue = document.getElementById('qrScaleValue');
if (qrImg && qrOpacitySlider) {
const opacity = parseFloat(qrImg.style.opacity) || 1;
qrOpacitySlider.value = Math.round(opacity * 100);
qrOpacityValue.textContent = Math.round(opacity * 100) + '%';
}
if (qrScaleSlider) {
const size = parseInt(element.style.width) || 100;
qrScaleSlider.value = size;
qrScaleValue.textContent = size + '%';
}
} else if (element.id === 'bgImage') {
// 选中背景图
editorToolbar.classList.add('active');
@@ -3206,16 +3259,24 @@
});
// 绘制二维码
const qrImages = container.querySelectorAll('img[data-type="qrcode"]');
for (const qrImg of qrImages) {
if (!qrImg.classList.contains('layer-hidden')) {
const rect = qrImg.getBoundingClientRect();
const qrWrappers = container.querySelectorAll('.qr-item');
for (const qrWrapper of qrWrappers) {
if (!qrWrapper.classList.contains('layer-hidden')) {
const qrImg = qrWrapper.querySelector('img');
if (!qrImg) continue;
const rect = qrWrapper.getBoundingClientRect();
const containerRect = container.getBoundingClientRect();
const x = (rect.left - containerRect.left) * scale;
const y = (rect.top - containerRect.top) * scale;
const w = rect.width * scale;
const h = rect.height * scale;
// 应用透明度
const opacity = parseFloat(qrImg.style.opacity) || 1;
ctx.save();
ctx.globalAlpha = opacity;
// 确保图片已加载
if (qrImg.complete && qrImg.naturalWidth > 0) {
ctx.drawImage(qrImg, x, y, w, h);
@@ -3231,6 +3292,8 @@
setTimeout(resolve, 100);
});
}
ctx.restore();
}
}