feat: 添加图片编辑器,与文本共用工具栏,选中切换编辑面板,支持图片透明度调节
This commit is contained in:
@@ -56,7 +56,8 @@
|
|||||||
16. 顶部工具栏新增层叠图,可添加多张层叠图,单击选中状态可缩放删除自由移动位置,置于背景图之上,输入框与层叠图点击只能同时选中一个
|
16. 顶部工具栏新增层叠图,可添加多张层叠图,单击选中状态可缩放删除自由移动位置,置于背景图之上,输入框与层叠图点击只能同时选中一个
|
||||||
17. 层叠图添加辅助线
|
17. 层叠图添加辅助线
|
||||||
18. 可添加多个文本框,以及文本框删除功能
|
18. 可添加多个文本框,以及文本框删除功能
|
||||||
19. 添加图片编辑器工具栏,图片编辑器与文本编辑器共用同一位置工具栏,选中对应元素切换对应编辑面板,点击空白出隐藏面板,修复层叠图不可移动问题
|
19. 添加图片编辑器工具栏,图片编辑器与文本编辑器共用同一位置工具栏,选中对应元素切换对应编辑面板,点击空白处隐藏面板
|
||||||
|
20. 当选择文字的时候工具栏对应出现文字编辑器,当选择图片的时候工具栏对应出现图片编辑器,点击其他位置时隐藏工具栏
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -79,12 +79,15 @@ html, body {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 文本编辑器工具栏 */
|
/* 编辑器工具栏(文本/图片共用) */
|
||||||
.text-editor-toolbar {
|
.editor-toolbar {
|
||||||
|
position: absolute;
|
||||||
|
top: 49px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
|
||||||
padding: 10px 16px;
|
padding: 10px 16px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-bottom: 1px solid #e0e0e0;
|
border-bottom: 1px solid #e0e0e0;
|
||||||
@@ -92,13 +95,25 @@ html, body {
|
|||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.2s;
|
transition: opacity 0.2s;
|
||||||
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-editor-toolbar.active {
|
.editor-toolbar.active {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toolbar-group {
|
||||||
|
display: none;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-group.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.toolbar-btn {
|
.toolbar-btn {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
@@ -150,6 +165,14 @@ html, body {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opacity-slider {
|
||||||
|
width: 120px;
|
||||||
|
height: 40px;
|
||||||
|
cursor: pointer;
|
||||||
|
accent-color: #4a90e2;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* 字号滚轮选择器 */
|
/* 字号滚轮选择器 */
|
||||||
.roller-picker {
|
.roller-picker {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
14
index.html
14
index.html
@@ -16,8 +16,10 @@
|
|||||||
<button class="btn btn-primary" id="saveBtn">保存/预览</button>
|
<button class="btn btn-primary" id="saveBtn">保存/预览</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 文本编辑器工具栏 -->
|
<!-- 编辑器工具栏(文本/图片共用) -->
|
||||||
<div class="text-editor-toolbar" id="textEditorToolbar">
|
<div class="editor-toolbar" id="editorToolbar">
|
||||||
|
<!-- 文本编辑工具 -->
|
||||||
|
<div class="toolbar-group text-tools" id="textTools">
|
||||||
<button class="toolbar-btn" id="boldBtn" title="加粗">B</button>
|
<button class="toolbar-btn" id="boldBtn" title="加粗">B</button>
|
||||||
<button class="toolbar-btn italic" id="italicBtn" title="斜体">I</button>
|
<button class="toolbar-btn italic" id="italicBtn" title="斜体">I</button>
|
||||||
<div class="toolbar-divider"></div>
|
<div class="toolbar-divider"></div>
|
||||||
@@ -45,6 +47,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 图片编辑工具 -->
|
||||||
|
<div class="toolbar-group image-tools" id="imageTools">
|
||||||
|
<label class="toolbar-label">
|
||||||
|
<span>透明度</span>
|
||||||
|
<input type="range" id="opacitySlider" min="0" max="100" value="100" class="opacity-slider">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 图片展示区 -->
|
<!-- 图片展示区 -->
|
||||||
<div class="canvas-area" id="canvasArea">
|
<div class="canvas-area" id="canvasArea">
|
||||||
|
|||||||
49
js/script.js
49
js/script.js
@@ -14,7 +14,10 @@
|
|||||||
const exportCanvas = document.getElementById('exportCanvas');
|
const exportCanvas = document.getElementById('exportCanvas');
|
||||||
const longPressTip = document.getElementById('longPressTip');
|
const longPressTip = document.getElementById('longPressTip');
|
||||||
const canvasArea = document.getElementById('canvasArea');
|
const canvasArea = document.getElementById('canvasArea');
|
||||||
const textEditorToolbar = document.getElementById('textEditorToolbar');
|
const editorToolbar = document.getElementById('editorToolbar');
|
||||||
|
const textTools = document.getElementById('textTools');
|
||||||
|
const imageTools = document.getElementById('imageTools');
|
||||||
|
const opacitySlider = document.getElementById('opacitySlider');
|
||||||
const boldBtn = document.getElementById('boldBtn');
|
const boldBtn = document.getElementById('boldBtn');
|
||||||
const italicBtn = document.getElementById('italicBtn');
|
const italicBtn = document.getElementById('italicBtn');
|
||||||
const colorPicker = document.getElementById('colorPicker');
|
const colorPicker = document.getElementById('colorPicker');
|
||||||
@@ -101,15 +104,22 @@
|
|||||||
// 初始化图片滑动
|
// 初始化图片滑动
|
||||||
initImageDrag();
|
initImageDrag();
|
||||||
|
|
||||||
|
// 透明度滑块
|
||||||
|
opacitySlider.addEventListener('input', (e) => {
|
||||||
|
if (selectedOverlay) {
|
||||||
|
selectedOverlay.style.opacity = e.target.value / 100;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 点击空白区域取消选中
|
// 点击空白区域取消选中
|
||||||
document.addEventListener('click', (e) => {
|
document.addEventListener('click', (e) => {
|
||||||
// 只有点击真正的空白区域(不是输入框,不是图片容器,不是工具栏)才取消选中
|
// 只有点击真正的空白区域(不是输入框,不是图片容器,不是工具栏)才取消选中
|
||||||
const isTextInput = e.target.closest('.text-input');
|
const isTextInput = e.target.closest('.text-input');
|
||||||
const isImageContainer = e.target.closest('.image-container');
|
const isImageContainer = e.target.closest('.image-container');
|
||||||
const isToolbar = e.target.closest('.toolbar');
|
const isToolbar = e.target.closest('.toolbar');
|
||||||
const isTextEditorToolbar = e.target.closest('.text-editor-toolbar');
|
const isEditorToolbar = e.target.closest('.editor-toolbar');
|
||||||
|
|
||||||
if (!isTextInput && !isImageContainer && !isToolbar && !isTextEditorToolbar) {
|
if (!isTextInput && !isImageContainer && !isToolbar && !isEditorToolbar) {
|
||||||
deselectAll();
|
deselectAll();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -142,8 +152,8 @@
|
|||||||
}
|
}
|
||||||
// 隐藏辅助线
|
// 隐藏辅助线
|
||||||
hideGuides();
|
hideGuides();
|
||||||
// 隐藏文本编辑器工具栏
|
// 隐藏编辑器工具栏
|
||||||
textEditorToolbar.classList.remove('active');
|
editorToolbar.classList.remove('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 点击空白区域(不是层叠图和输入框)
|
// 点击空白区域(不是层叠图和输入框)
|
||||||
@@ -506,6 +516,15 @@
|
|||||||
}
|
}
|
||||||
selectedOverlay = overlayEl;
|
selectedOverlay = overlayEl;
|
||||||
overlayEl.classList.add('selected');
|
overlayEl.classList.add('selected');
|
||||||
|
|
||||||
|
// 显示编辑器工具栏和图片工具
|
||||||
|
editorToolbar.classList.add('active');
|
||||||
|
textTools.classList.remove('active');
|
||||||
|
imageTools.classList.add('active');
|
||||||
|
|
||||||
|
// 更新透明度滑块为当前层叠图的透明度
|
||||||
|
const currentOpacity = overlayEl.style.opacity || '1';
|
||||||
|
opacitySlider.value = parseFloat(currentOpacity) * 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算图片滑动边界
|
// 计算图片滑动边界
|
||||||
@@ -837,8 +856,10 @@
|
|||||||
element.classList.remove('editing');
|
element.classList.remove('editing');
|
||||||
element.contentEditable = 'false';
|
element.contentEditable = 'false';
|
||||||
|
|
||||||
// 显示文本编辑器工具栏
|
// 显示编辑器工具栏和文本工具
|
||||||
textEditorToolbar.classList.add('active');
|
editorToolbar.classList.add('active');
|
||||||
|
textTools.classList.add('active');
|
||||||
|
imageTools.classList.remove('active');
|
||||||
|
|
||||||
// 更新工具栏状态
|
// 更新工具栏状态
|
||||||
updateToolbarState(element);
|
updateToolbarState(element);
|
||||||
@@ -857,8 +878,10 @@
|
|||||||
element.classList.remove('selected');
|
element.classList.remove('selected');
|
||||||
element.contentEditable = 'true';
|
element.contentEditable = 'true';
|
||||||
|
|
||||||
// 显示文本编辑器工具栏
|
// 显示编辑器工具栏和文本工具
|
||||||
textEditorToolbar.classList.add('active');
|
editorToolbar.classList.add('active');
|
||||||
|
textTools.classList.add('active');
|
||||||
|
imageTools.classList.remove('active');
|
||||||
|
|
||||||
// 更新工具栏状态
|
// 更新工具栏状态
|
||||||
updateToolbarState(element);
|
updateToolbarState(element);
|
||||||
@@ -888,8 +911,8 @@
|
|||||||
element.contentEditable = 'false';
|
element.contentEditable = 'false';
|
||||||
element.blur();
|
element.blur();
|
||||||
editingInput = null;
|
editingInput = null;
|
||||||
// 隐藏文本编辑器工具栏
|
// 隐藏编辑器工具栏
|
||||||
textEditorToolbar.classList.remove('active');
|
editorToolbar.classList.remove('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新工具栏状态
|
// 更新工具栏状态
|
||||||
@@ -1314,8 +1337,8 @@
|
|||||||
selectedInput.classList.remove('selected');
|
selectedInput.classList.remove('selected');
|
||||||
selectedInput = null;
|
selectedInput = null;
|
||||||
}
|
}
|
||||||
// 隐藏文本编辑器工具栏
|
// 隐藏编辑器工具栏
|
||||||
textEditorToolbar.classList.remove('active');
|
editorToolbar.classList.remove('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化长按保存(只在3:5预览区域)
|
// 初始化长按保存(只在3:5预览区域)
|
||||||
|
|||||||
Reference in New Issue
Block a user