refactor: 优化文本编辑器工具栏功能,实现文字样式实时修改与双端显示适配

This commit is contained in:
Zhukj
2026-04-16 14:26:35 +08:00
parent a296d88d2c
commit 504ac42159
3 changed files with 67 additions and 41 deletions

View File

@@ -62,12 +62,13 @@
// 点击空白区域取消选中
document.addEventListener('click', (e) => {
// 只有点击真正的空白区域(不是输入框,不是图片容器)才取消选中
// 只有点击真正的空白区域(不是输入框,不是图片容器,不是工具栏)才取消选中
const isTextInput = e.target.closest('.text-input');
const isImageContainer = e.target.closest('.image-container');
const isToolbar = e.target.closest('.toolbar');
const isTextEditorToolbar = e.target.closest('.text-editor-toolbar');
if (!isTextInput && !isImageContainer && !isToolbar) {
if (!isTextInput && !isImageContainer && !isToolbar && !isTextEditorToolbar) {
deselectAll();
}
});
@@ -275,6 +276,12 @@
function handleStart(e) {
const isTouch = e.type === 'touchstart';
// 如果正在编辑此输入框,不处理拖拽事件,让浏览器处理文本选择
if (editingInput === element) {
return;
}
const clientX = isTouch ? e.touches[0].clientX : e.clientX;
const clientY = isTouch ? e.touches[0].clientY : e.clientY;
@@ -285,11 +292,6 @@
hasMoved = false;
isDragging = false;
// 如果正在编辑此输入框,不处理
if (editingInput === element) {
return;
}
// 选中此输入框
selectInput(element);
@@ -306,10 +308,6 @@
}
}, 150);
if (isTouch) {
e.preventDefault();
}
// 阻止事件冒泡,避免触发图片滑动
e.stopPropagation();
}
@@ -319,8 +317,13 @@
element.addEventListener('touchmove', handleMove, { passive: false });
function handleMove(e) {
// 如果正在编辑,不拦截事件,让浏览器处理文本选择
if (editingInput === element) {
return;
}
if (!isMouseDown) return;
if (!selectedInput || editingInput === element) return;
if (!selectedInput) return;
const isTouch = e.type === 'touchmove';
const clientX = isTouch ? e.touches[0].clientX : e.clientX;
@@ -348,16 +351,10 @@
const dy = clientY - startY;
element.style.left = (startLeft + dx) + 'px';
element.style.top = (startTop + dy) + 'px';
if (isTouch) {
e.preventDefault();
}
}
// 阻止事件冒泡和默认行为,确保输入框拖动完全独立,不影响背景图
// 阻止事件冒泡,避免触发图片滑动
e.stopPropagation();
if (isTouch) {
e.preventDefault();
}
}
// 鼠标/触摸释放
@@ -389,18 +386,17 @@
}
}
// 双击进入编辑模式
// 双击进入编辑模式(电脑端和移动端通用)
element.addEventListener('dblclick', (e) => {
e.stopPropagation();
startEdit(element);
});
// 触摸双击检测
// 触摸双击检测(移动端双击进入编辑)
let lastTapTime = 0;
element.addEventListener('touchend', (e) => {
const currentTime = Date.now();
if (currentTime - lastTapTime < 300) {
e.preventDefault();
e.stopPropagation();
startEdit(element);
}
@@ -436,18 +432,22 @@
element.classList.add('editing');
element.classList.remove('selected');
element.contentEditable = 'true';
element.focus();
// 更新工具栏状态
updateToolbarState(element);
// 光标定位到末尾
const range = document.createRange();
const sel = window.getSelection();
range.selectNodeContents(element);
range.collapse(false);
sel.removeAllRanges();
sel.addRange(range);
// 如果没有选中文本,则定位光标到末尾
setTimeout(() => {
const sel = window.getSelection();
if (sel.isCollapsed) {
const range = document.createRange();
range.selectNodeContents(element);
range.collapse(false);
sel.removeAllRanges();
sel.addRange(range);
}
element.focus();
}, 10);
if ('virtualKeyboard' in navigator) {
navigator.virtualKeyboard.show();
@@ -567,31 +567,46 @@
// 加粗按钮
boldBtn.addEventListener('click', () => {
if (!editingInput) return;
const isBold = boldBtn.classList.contains('active');
if (isBold) {
editingInput.style.fontWeight = 'normal';
const selection = window.getSelection();
if (selection.rangeCount > 0 && !selection.isCollapsed) {
document.execCommand('bold', false, null);
} else {
editingInput.style.fontWeight = 'bold';
const isBold = boldBtn.classList.contains('active');
if (isBold) {
editingInput.style.fontWeight = 'normal';
} else {
editingInput.style.fontWeight = 'bold';
}
boldBtn.classList.toggle('active');
}
boldBtn.classList.toggle('active');
});
// 斜体按钮
italicBtn.addEventListener('click', () => {
if (!editingInput) return;
const isItalic = italicBtn.classList.contains('active');
if (isItalic) {
editingInput.style.fontStyle = 'normal';
const selection = window.getSelection();
if (selection.rangeCount > 0 && !selection.isCollapsed) {
document.execCommand('italic', false, null);
} else {
editingInput.style.fontStyle = 'italic';
const isItalic = italicBtn.classList.contains('active');
if (isItalic) {
editingInput.style.fontStyle = 'normal';
} else {
editingInput.style.fontStyle = 'italic';
}
italicBtn.classList.toggle('active');
}
italicBtn.classList.toggle('active');
});
// 颜色选择器
colorPicker.addEventListener('input', () => {
if (!editingInput) return;
editingInput.style.color = colorPicker.value;
const selection = window.getSelection();
if (selection.rangeCount > 0 && !selection.isCollapsed) {
document.execCommand('foreColor', false, colorPicker.value);
} else {
editingInput.style.color = colorPicker.value;
}
});
// 字体选择器