diff --git a/src/components/RichTextEditor.vue b/src/components/RichTextEditor.vue index c84bbee..df72eb8 100644 --- a/src/components/RichTextEditor.vue +++ b/src/components/RichTextEditor.vue @@ -39,7 +39,7 @@ const dragState = ref({ isLongPress: false, indicator: null, lastCheckTime: 0, - lastMoveTime: 0 + lastMoveTime: 0, }) // 初始化编辑器内容 @@ -64,15 +64,15 @@ onMounted(() => { console.log('Editor initialized without initial content') } } - + // 记录初始视口高度 initialViewportHeight.value = window.visualViewport?.height || window.innerHeight console.log('Initial viewport height:', initialViewportHeight.value) - + // 初始化CSS变量 document.documentElement.style.setProperty('--viewport-height', `${initialViewportHeight.value}px`) console.log('Set viewport height CSS variable') - + // 添加虚拟键盘检测事件监听器 if (window.visualViewport) { console.log('Adding viewport resize listener') @@ -81,7 +81,7 @@ onMounted(() => { console.log('Adding window resize listener') window.addEventListener('resize', handleWindowResize) } - + // 为已有图片添加拖拽事件监听器 setTimeout(() => { console.log('Adding drag event listeners to existing images') @@ -90,14 +90,14 @@ onMounted(() => { imageContainers.forEach(container => { const img = container.querySelector('img.editor-image') if (!img) return - + console.log('Adding touch listeners to image:', img) // 添加触摸事件监听器 container.addEventListener('touchstart', handleTouchStart) container.addEventListener('touchmove', handleTouchMove) container.addEventListener('touchend', handleTouchEnd) container.addEventListener('touchcancel', handleTouchCancel) - + // 为删除按钮添加点击事件 let deleteBtn = container.querySelector('.image-delete-btn') if (!deleteBtn) { @@ -105,86 +105,81 @@ onMounted(() => { console.log('Delete button not found in mounted hook, creating new one') deleteBtn = document.createElement('div') deleteBtn.className = 'image-delete-btn' - deleteBtn.style.cssText = 'position: absolute; top: 8px; right: 8px; width: 24px; height: 24px; cursor: pointer; z-index: 1000; display: none; transition: opacity 0.2s ease; touch-action: manipulation;' container.appendChild(deleteBtn) } - + if (deleteBtn) { // 先移除可能已有的事件监听器,避免重复 deleteBtn.removeEventListener('click', null) deleteBtn.removeEventListener('touchend', null) - - deleteBtn.addEventListener('click', function(e) { - e.stopPropagation(); - container.remove(); - handleInput(); - }); - - deleteBtn.addEventListener('touchend', function(e) { - e.stopPropagation(); - container.remove(); - handleInput(); - }); + + deleteBtn.addEventListener('click', function (e) { + e.stopPropagation() + container.remove() + handleInput() + }) + + deleteBtn.addEventListener('touchend', function (e) { + e.stopPropagation() + container.remove() + handleInput() + }) } - + // 为图片容器添加短按事件以显示/隐藏删除按钮 // 先移除可能已有的事件监听器,避免重复 - const touchStartHandler = container._touchStartHandler; - const touchEndHandler = container._touchEndHandler; - + const touchStartHandler = container._touchStartHandler + const touchEndHandler = container._touchEndHandler + if (touchStartHandler) { - container.removeEventListener('touchstart', touchStartHandler); + container.removeEventListener('touchstart', touchStartHandler) } - + if (touchEndHandler) { - container.removeEventListener('touchend', touchEndHandler); + container.removeEventListener('touchend', touchEndHandler) } - - let touchStartTime = 0; - const newTouchStartHandler = function(e) { - touchStartTime = Date.now(); - }; - - const newTouchEndHandler = function(e) { - const touchDuration = Date.now() - touchStartTime; - console.log('Touch end event triggered in mounted hook, duration:', touchDuration, 'isLongPress:', dragState.value.isLongPress); + + let touchStartTime = 0 + const newTouchStartHandler = function (e) { + touchStartTime = Date.now() + } + + const newTouchEndHandler = function (e) { + const touchDuration = Date.now() - touchStartTime + console.log('Touch end event triggered in mounted hook, duration:', touchDuration, 'isLongPress:', dragState.value.isLongPress) // 短按(小于200ms)且非长按拖拽状态时切换删除按钮显示 if (touchDuration < 200 && !dragState.value.isLongPress) { - e.stopPropagation(); - console.log('Short tap detected in mounted hook, toggling delete button visibility'); + e.stopPropagation() + console.log('Short tap detected in mounted hook, toggling delete button visibility') // 切换删除按钮的显示状态 if (deleteBtn) { - console.log('Current delete button display style in mounted hook:', deleteBtn.style.display); + console.log('Current delete button display style in mounted hook:', deleteBtn.style.display) // 检查删除按钮当前是否可见 - const computedStyle = getComputedStyle(deleteBtn); - const isCurrentlyVisible = deleteBtn.style.display === 'block' || - computedStyle.display === 'block' || - (deleteBtn.style.display !== 'none' && - computedStyle.display !== 'none'); - - console.log('Delete button current styles in mounted hook - inline:', deleteBtn.style.display, 'computed:', computedStyle.display); - + const isCurrentlyVisible = deleteBtn.classList.contains('visible') + + console.log('Delete button current styles in mounted hook - inline:', deleteBtn.style.display, 'computed:', computedStyle.display) + if (isCurrentlyVisible) { - deleteBtn.style.display = 'none'; - console.log('Delete button hidden in mounted hook'); + deleteBtn.classList.remove('visible') + console.log('Delete button hidden in mounted hook') } else { - deleteBtn.style.display = 'block'; - console.log('Delete button displayed in mounted hook'); + deleteBtn.classList.add('visible') + console.log('Delete button displayed in mounted hook') } } else { - console.log('Delete button not found in mounted hook'); + console.log('Delete button not found in mounted hook') } } else { - console.log('Not a short tap or isLongPress is true in mounted hook'); + console.log('Not a short tap or isLongPress is true in mounted hook') } - }; - - container.addEventListener('touchstart', newTouchStartHandler); - container.addEventListener('touchend', newTouchEndHandler); - + } + + container.addEventListener('touchstart', newTouchStartHandler) + container.addEventListener('touchend', newTouchEndHandler) + // 保存事件处理函数的引用,以便后续移除 - container._touchStartHandler = newTouchStartHandler; - container._touchEndHandler = newTouchEndHandler; + container._touchStartHandler = newTouchStartHandler + container._touchEndHandler = newTouchEndHandler }) }, 0) }) @@ -196,7 +191,7 @@ onUnmounted(() => { } else { window.removeEventListener('resize', handleWindowResize) } - + // 清理所有图片容器的事件监听器 if (editorRef.value) { const imageContainers = editorRef.value.querySelectorAll('.image-container') @@ -206,21 +201,21 @@ onUnmounted(() => { container.removeEventListener('touchmove', handleTouchMove) container.removeEventListener('touchend', handleTouchEnd) container.removeEventListener('touchcancel', handleTouchCancel) - + // 移除短按事件监听器 - const touchStartHandler = container._touchStartHandler; - const touchEndHandler = container._touchEndHandler; - + const touchStartHandler = container._touchStartHandler + const touchEndHandler = container._touchEndHandler + if (touchStartHandler) { - container.removeEventListener('touchstart', touchStartHandler); - delete container._touchStartHandler; + container.removeEventListener('touchstart', touchStartHandler) + delete container._touchStartHandler } - + if (touchEndHandler) { - container.removeEventListener('touchend', touchEndHandler); - delete container._touchEndHandler; + container.removeEventListener('touchend', touchEndHandler) + delete container._touchEndHandler } - + // 移除删除按钮事件监听器 const deleteBtn = container.querySelector('.image-delete-btn') if (deleteBtn) { @@ -235,39 +230,39 @@ onUnmounted(() => { // 定义富文本编辑器的所有工具按钮及其功能 const tools = ref([ { - name: 'bold', // 加粗工具 + name: 'bold', // 加粗工具 icon: '/assets/icons/drawable-xxhdpi/rtf_bold_normal.9.png', - action: () => formatText('bold'), // 执行加粗格式化 - active: false, // 工具是否处于激活状态 + action: () => formatText('bold'), // 执行加粗格式化 + active: false, // 工具是否处于激活状态 }, { - name: 'center', // 居中对齐工具 + name: 'center', // 居中对齐工具 icon: '/assets/icons/drawable-xxhdpi/rtf_center_normal.9.png', - action: () => formatText('justifyCenter'), // 执行居中对齐格式化 + action: () => formatText('justifyCenter'), // 执行居中对齐格式化 active: false, }, { - name: 'todo', // 待办事项工具 + name: 'todo', // 待办事项工具 icon: '/assets/icons/drawable-xxhdpi/rtf_gtasks_normal.9.png', action: () => formatText('insertTodoList'), // 插入待办事项列表 active: false, }, { - name: 'list', // 无序列表工具 + name: 'list', // 无序列表工具 icon: '/assets/icons/drawable-xxhdpi/rtf_list_normal.9.png', action: () => formatText('insertUnorderedList'), // 插入无序列表 active: false, }, { - name: 'header', // 标题工具 + name: 'header', // 标题工具 icon: '/assets/icons/drawable-xxhdpi/rtf_header_normal.9.png', - action: () => formatText('formatBlock', 'h2'), // 格式化为二级标题 + action: () => formatText('formatBlock', 'h2'), // 格式化为二级标题 active: false, }, { - name: 'quote', // 引用工具 + name: 'quote', // 引用工具 icon: '/assets/icons/drawable-xxhdpi/rtf_quot_normal.9.png', - action: () => insertQuote(), // 插入引用格式 + action: () => insertQuote(), // 插入引用格式 active: false, }, ]) @@ -276,7 +271,7 @@ const tools = ref([ const handleInput = () => { if (editorRef.value) { // 获取编辑器内容(不清理,保持功能完整) - let innerHTML = editorRef.value.innerHTML; + let innerHTML = editorRef.value.innerHTML // 处理换行符,确保在段落之间有明确的分隔 innerHTML = innerHTML.replace(/<\/p>
/g, '
\n') @@ -332,9 +327,7 @@ const isInListOrQuote = () => { let current = container.nodeType === Node.TEXT_NODE ? container.parentElement : container while (current && current !== editorRef.value) { // 检查是否在列表、引用或待办事项中 - if (current.tagName === 'UL' || current.tagName === 'OL' || current.tagName === 'LI' || - current.tagName === 'BLOCKQUOTE' || current.classList.contains('quote-content') || - current.classList.contains('todo-container')) { + if (current.tagName === 'UL' || current.tagName === 'OL' || current.tagName === 'LI' || current.tagName === 'BLOCKQUOTE' || current.classList.contains('quote-content') || current.classList.contains('todo-container')) { return true } current = current.parentElement @@ -494,20 +487,20 @@ const insertTodoList = () => { // 创建待办事项容器 const todoContainer = document.createElement('div') - todoContainer.contentEditable = false // 容器本身不可编辑 + todoContainer.contentEditable = false // 容器本身不可编辑 todoContainer.className = 'todo-container' // 创建图标元素(复选框) const icon = document.createElement('img') icon.className = 'todo-icon' - icon.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png' // 未完成状态图标 + icon.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png' // 未完成状态图标 icon.alt = '待办事项' // 创建内容容器(可编辑区域) const contentSpan = document.createElement('div') - contentSpan.contentEditable = true // 内容区域可编辑 + contentSpan.contentEditable = true // 内容区域可编辑 contentSpan.className = 'todo-content' - contentSpan.textContent = '待办事项' // 默认文本 + contentSpan.textContent = '待办事项' // 默认文本 // 组装元素:将图标和内容区域添加到容器中 todoContainer.appendChild(icon) @@ -544,16 +537,16 @@ const insertTodoList = () => { // 根据当前状态切换图标和样式 if (this.src.includes('rtf_icon_gtasks.png')) { // 切换到完成状态 - this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks_light.png' // 完成状态图标 - contentSpan.style.color = 'var(--text-tertiary)' // 灰色文字 - contentSpan.style.textDecoration = 'line-through' // 添加删除线 + this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks_light.png' // 完成状态图标 + contentSpan.style.color = 'var(--text-tertiary)' // 灰色文字 + contentSpan.style.textDecoration = 'line-through' // 添加删除线 } else { // 切换到未完成状态 - this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png' // 未完成状态图标 - contentSpan.style.color = 'var(--note-content)' // 正常文字颜色 - contentSpan.style.textDecoration = 'none' // 移除删除线 + this.src = '/assets/icons/drawable-xxhdpi/rtf_icon_gtasks.png' // 未完成状态图标 + contentSpan.style.color = 'var(--note-content)' // 正常文字颜色 + contentSpan.style.textDecoration = 'none' // 移除删除线 } - handleInput() // 触发内容更新 + handleInput() // 触发内容更新 }) // 添加事件监听器到内容区域,监听内容变化和按键事件 @@ -568,8 +561,8 @@ const insertTodoList = () => { }, 0) } - contentSpan.addEventListener('input', checkContent) // 内容输入时检查 - contentSpan.addEventListener('blur', checkContent) // 失去焦点时检查 + contentSpan.addEventListener('input', checkContent) // 内容输入时检查 + contentSpan.addEventListener('blur', checkContent) // 失去焦点时检查 // 添加焦点事件监听器,确保工具栏在待办事项获得焦点时保持可见 contentSpan.addEventListener('focus', () => { @@ -741,7 +734,7 @@ const resetDragState = () => { clearTimeout(dragState.value.longPressTimer) dragState.value.longPressTimer = null } - + // 重置所有拖拽状态 dragState.value.isLongPress = false dragState.value.draggedImage = null @@ -749,7 +742,7 @@ const resetDragState = () => { dragState.value.startY = 0 dragState.value.currentY = 0 dragState.value.lastMoveTime = 0 - + // 移除拖拽指示器 if (dragState.value.indicator) { const indicator = dragState.value.indicator @@ -761,7 +754,7 @@ const resetDragState = () => { }, 150) dragState.value.indicator = null } - + // 重置所有图片的拖拽样式 if (editorRef.value) { const draggedImages = editorRef.value.querySelectorAll('.editor-image.dragging') @@ -810,14 +803,13 @@ const insertImage = () => { // 检查选区是否在图片容器内部,如果是则调整到容器后面 const startContainer = range.startContainer let imageContainer = null - + // 如果startContainer是图片容器本身 if (startContainer.classList && startContainer.classList.contains('image-container')) { imageContainer = startContainer } // 如果startContainer是图片容器的子元素 - else if (startContainer.parentNode && startContainer.parentNode.classList && - startContainer.parentNode.classList.contains('image-container')) { + else if (startContainer.parentNode && startContainer.parentNode.classList && startContainer.parentNode.classList.contains('image-container')) { imageContainer = startContainer.parentNode } // 向上查找父元素 @@ -831,7 +823,7 @@ const insertImage = () => { parent = parent.parentNode } } - + // 如果选区在图片容器内部,调整到容器后面 if (imageContainer) { console.log('Selection is inside image container, adjusting range') @@ -845,7 +837,7 @@ const insertImage = () => { imgContainer.className = 'image-container' imgContainer.style.position = 'relative' imgContainer.style.display = 'inline-block' - + // 创建图片元素 const img = document.createElement('img') img.src = imageDataUrl @@ -869,18 +861,17 @@ const insertImage = () => { img.style.webkitTouchCallout = 'none' // 防止长按弹出菜单 img.style.webkitTapHighlightColor = 'transparent' // 防止点击高亮 img.draggable = true - + // 创建删除按钮 const deleteBtn = document.createElement('div') deleteBtn.className = 'image-delete-btn' - deleteBtn.style.cssText = 'position: absolute; top: 8px; right: 8px; width: 24px; height: 24px; cursor: pointer; z-index: 1000; display: none; transition: opacity 0.2s ease; touch-action: manipulation;' - + // 将图片和删除按钮添加到容器中 imgContainer.appendChild(img) imgContainer.appendChild(deleteBtn) - + console.log('Created image element:', img) - + // 创建一个临时图片来获取原始尺寸 const tempImg = new Image() tempImg.onload = function () { @@ -924,89 +915,79 @@ const insertImage = () => { imgContainer.removeEventListener('touchmove', handleTouchMove) imgContainer.removeEventListener('touchend', handleTouchEnd) imgContainer.removeEventListener('touchcancel', handleTouchCancel) - + // 重新添加事件监听器 imgContainer.addEventListener('touchstart', handleTouchStart) imgContainer.addEventListener('touchmove', handleTouchMove) imgContainer.addEventListener('touchend', handleTouchEnd) imgContainer.addEventListener('touchcancel', handleTouchCancel) - + // 为删除按钮添加点击事件(鼠标和触摸) // 先移除可能已有的事件监听器,避免重复 deleteBtn.removeEventListener('click', null) deleteBtn.removeEventListener('touchend', null) - - deleteBtn.addEventListener('click', function(e) { - e.stopPropagation(); - imgContainer.remove(); - handleInput(); - }); - - deleteBtn.addEventListener('touchend', function(e) { - e.stopPropagation(); - imgContainer.remove(); - handleInput(); - }); - + + deleteBtn.addEventListener('click', function (e) { + e.stopPropagation() + imgContainer.remove() + handleInput() + }) + + deleteBtn.addEventListener('touchend', function (e) { + e.stopPropagation() + imgContainer.remove() + handleInput() + }) + // 为图片容器添加短按事件以显示/隐藏删除按钮 - let touchStartTime = 0; - const touchStartHandler = function(e) { - touchStartTime = Date.now(); - }; - - const touchEndHandler = function(e) { - const touchDuration = Date.now() - touchStartTime; - console.log('Touch end event triggered, duration:', touchDuration, 'isLongPress:', dragState.value.isLongPress); + let touchStartTime = 0 + const touchStartHandler = function (e) { + touchStartTime = Date.now() + } + + const touchEndHandler = function (e) { + const touchDuration = Date.now() - touchStartTime + console.log('Touch end event triggered, duration:', touchDuration, 'isLongPress:', dragState.value.isLongPress) // 短按(小于200ms)且非长按拖拽状态时切换删除按钮显示 if (touchDuration < 200 && !dragState.value.isLongPress) { - e.stopPropagation(); - console.log('Short tap detected, toggling delete button visibility'); + e.stopPropagation() + console.log('Short tap detected, toggling delete button visibility') // 切换删除按钮的显示状态 if (deleteBtn) { - console.log('Current delete button display style:', deleteBtn.style.display); + console.log('Current delete button display style:', deleteBtn.style.display) // 检查删除按钮当前是否可见 - const computedStyle = getComputedStyle(deleteBtn); - const isCurrentlyVisible = deleteBtn.style.display === 'block' || - computedStyle.display === 'block' || - (deleteBtn.style.display !== 'none' && - computedStyle.display !== 'none'); - - console.log('Delete button current styles - inline:', deleteBtn.style.display, 'computed:', computedStyle.display); - console.log('Delete button background image:', computedStyle.backgroundImage); - console.log('Delete button width:', computedStyle.width, 'height:', computedStyle.height); - console.log('Delete button position:', computedStyle.position); - console.log('Delete button z-index:', computedStyle.zIndex); - + const isCurrentlyVisible = deleteBtn.classList.contains('visible') + + console.log('Delete button current styles - inline:', deleteBtn.style.display) + if (isCurrentlyVisible) { - deleteBtn.style.display = 'none'; - console.log('Delete button hidden'); + deleteBtn.classList.remove('visible') + console.log('Delete button hidden') } else { - deleteBtn.style.display = 'block'; - console.log('Delete button displayed'); - // 添加调试样式以确保可见 - deleteBtn.style.backgroundColor = 'rgba(255, 0, 0, 0.3)'; // 半透明红色背景用于调试 + deleteBtn.classList.add('visible') + console.log('Delete button displayed') } } else { - console.log('Delete button not found'); + console.log('Delete button not found') } } else { - console.log('Not a short tap or isLongPress is true'); + console.log('Not a short tap or isLongPress is true') } - }; - - imgContainer.addEventListener('touchstart', touchStartHandler); - imgContainer.addEventListener('touchend', touchEndHandler); - + } + + imgContainer.addEventListener('touchstart', touchStartHandler) + imgContainer.addEventListener('touchend', touchEndHandler) + // 保存事件处理函数的引用,以便后续移除 - imgContainer._touchStartHandler = touchStartHandler; - imgContainer._touchEndHandler = touchEndHandler; - + imgContainer._touchStartHandler = touchStartHandler + imgContainer._touchEndHandler = touchEndHandler + console.log('Added touch event listeners') // 插入图片容器到当前光标位置 range.insertNode(imgContainer) console.log('Inserted image container into editor') - + // 调试信息 console.log('Image container inserted:', imgContainer) console.log('Next sibling (should be drag handle):', imgContainer.nextSibling) @@ -1015,23 +996,23 @@ const insertImage = () => { const br = document.createElement('br') imgContainer.parentNode.insertBefore(br, imgContainer.nextSibling) console.log('Added line break after image container') - + // 修正选区位置,避免嵌套插入 // 使用setTimeout确保DOM更新完成后再设置选区 setTimeout(() => { - const newRange = document.createRange(); - newRange.setStartAfter(br); - newRange.collapse(true); - const sel = window.getSelection(); - sel.removeAllRanges(); - sel.addRange(newRange); - + const newRange = document.createRange() + newRange.setStartAfter(br) + newRange.collapse(true) + const sel = window.getSelection() + sel.removeAllRanges() + sel.addRange(newRange) + // 重新聚焦到编辑器 if (editorRef.value) { editorRef.value.focus() console.log('Focused editor') } - }, 0); + }, 0) // 触发输入事件更新内容 handleInput() @@ -1104,10 +1085,10 @@ const handleKeydown = e => { } // 处理触摸开始事件 -const handleTouchStart = (e) => { +const handleTouchStart = e => { const img = e.target if (!img.classList.contains('editor-image')) return - + // 防止图片被选中 - 在触摸开始时就应用 img.style.userSelect = 'none' img.style.webkitUserSelect = 'none' @@ -1115,30 +1096,30 @@ const handleTouchStart = (e) => { img.style.msUserSelect = 'none' img.style.webkitTouchCallout = 'none' img.style.webkitTapHighlightColor = 'transparent' - + // 清除之前的定时器 if (dragState.value.longPressTimer) { clearTimeout(dragState.value.longPressTimer) } - + // 记录触摸开始位置 dragState.value.startX = e.touches[0].clientX dragState.value.startY = e.touches[0].clientY - + // 设置长按检测定时器(500毫秒) dragState.value.longPressTimer = setTimeout(() => { dragState.value.isLongPress = true dragState.value.draggedImage = img dragState.value.startY = e.touches[0].clientY dragState.value.currentY = e.touches[0].clientY - + // 添加拖拽样式 img.classList.add('dragging') img.style.opacity = '0.85' img.style.transform = 'scale(0.96)' img.style.zIndex = '999' img.style.transition = 'all 0.15s cubic-bezier(0.25, 0.46, 0.45, 0.94)' - + // 添加拖拽指示器 const indicator = document.createElement('div') indicator.className = 'drag-indicator' @@ -1158,42 +1139,42 @@ const handleTouchStart = (e) => { indicator.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.3)' indicator.textContent = '拖拽排序' document.body.appendChild(indicator) - + // 渐显指示器 setTimeout(() => { indicator.style.opacity = '1' }, 1) - + // 保存指示器引用以便后续移除 dragState.value.indicator = indicator - + // 添加震动反馈(如果设备支持) if (navigator.vibrate) { navigator.vibrate(15) } - + // 阻止页面滚动 e.preventDefault() }, 500) // 500毫秒长按触发拖拽 } // 处理触摸移动事件 -const handleTouchMove = (e) => { +const handleTouchMove = e => { if (!dragState.value.longPressTimer && !dragState.value.isLongPress) return - + const img = dragState.value.draggedImage const currentX = e.touches[0].clientX const currentY = e.touches[0].clientY - + // 防止图片被选中 e.preventDefault() - + // 如果还没有触发长按,检查是否移动过多(超过6px则取消长按) if (!dragState.value.isLongPress) { const deltaX = Math.abs(currentX - dragState.value.startX) const deltaY = Math.abs(currentY - dragState.value.startY) const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY) - + if (distance > 6) { // 移动过多,取消长按 if (dragState.value.longPressTimer) { @@ -1203,28 +1184,28 @@ const handleTouchMove = (e) => { return } } - + if (!dragState.value.isLongPress || !img) return - + e.preventDefault() // 阻止页面滚动 - + dragState.value.currentY = currentY - + // 计算位移 const deltaY = dragState.value.currentY - dragState.value.startY - + // 使用requestAnimationFrame确保流畅的动画 requestAnimationFrame(() => { // 更新图片位置,添加缓动效果 const easeFactor = 0.95 // 调整缓动因子使拖拽更跟手 img.style.transform = `translateY(${deltaY * easeFactor}px) scale(0.96)` - }); - + }) + // 使用节流优化,避免过于频繁的检查 if (!dragState.value.lastMoveTime) { dragState.value.lastMoveTime = 0 } - + const now = Date.now() // 限制检查频率为每16ms一次(约60fps),提高响应速度 if (now - dragState.value.lastMoveTime >= 16) { @@ -1234,26 +1215,26 @@ const handleTouchMove = (e) => { } // 处理触摸结束事件 -const handleTouchEnd = (e) => { +const handleTouchEnd = e => { // 清除长按定时器 if (dragState.value.longPressTimer) { clearTimeout(dragState.value.longPressTimer) dragState.value.longPressTimer = null } - + if (!dragState.value.isLongPress || !dragState.value.draggedImage) { dragState.value.isLongPress = false return } - + // 重置拖拽状态 const img = dragState.value.draggedImage - + // 添加更流畅的释放动画 img.style.transition = 'all 0.15s cubic-bezier(0.25, 0.46, 0.45, 0.94)' img.style.transform = 'translateY(0) scale(1)' img.style.opacity = '1' - + // 移除拖拽指示器 if (dragState.value.indicator) { const indicator = dragState.value.indicator @@ -1265,12 +1246,12 @@ const handleTouchEnd = (e) => { } }, 100) } - + // 添加震动反馈(如果设备支持) if (navigator.vibrate) { navigator.vibrate(8) } - + // 延迟重置样式以显示动画 setTimeout(() => { if (img) { @@ -1279,39 +1260,39 @@ const handleTouchEnd = (e) => { img.style.transition = '' } }, 150) - + // 重置状态 dragState.value.isLongPress = false dragState.value.draggedImage = null dragState.value.startY = 0 dragState.value.currentY = 0 dragState.value.indicator = null - + // 触发内容更新 handleInput() } // 处理触摸取消事件 -const handleTouchCancel = (e) => { +const handleTouchCancel = e => { // 清除长按定时器 if (dragState.value.longPressTimer) { clearTimeout(dragState.value.longPressTimer) dragState.value.longPressTimer = null } - + if (!dragState.value.isLongPress || !dragState.value.draggedImage) { dragState.value.isLongPress = false return } - + // 重置拖拽状态 const img = dragState.value.draggedImage - + // 添加取消动画 img.style.transition = 'all 0.15s cubic-bezier(0.25, 0.46, 0.45, 0.94)' img.style.transform = 'translateY(0) scale(1)' img.style.opacity = '1' - + // 移除拖拽指示器 if (dragState.value.indicator) { const indicator = dragState.value.indicator @@ -1323,7 +1304,7 @@ const handleTouchCancel = (e) => { } }, 100) } - + // 延迟重置样式以显示动画 setTimeout(() => { if (img) { @@ -1332,7 +1313,7 @@ const handleTouchCancel = (e) => { img.style.transition = '' } }, 150) - + // 重置状态 dragState.value.isLongPress = false dragState.value.draggedImage = null @@ -1345,26 +1326,26 @@ const handleTouchCancel = (e) => { const checkAndSwapImages = (draggedImg, deltaY) => { const allImages = Array.from(editorRef.value.querySelectorAll('.editor-image')) const draggedIndex = allImages.indexOf(draggedImg) - + if (draggedIndex === -1) return - + // 计算拖拽图片的中心位置 const draggedRect = draggedImg.getBoundingClientRect() const draggedCenterY = draggedRect.top + draggedRect.height / 2 + deltaY * 0.95 // 调整缓动因子以匹配触摸移动 - + // 查找最近的图片进行交换 for (let i = 0; i < allImages.length; i++) { if (i === draggedIndex) continue - + const targetImg = allImages[i] const targetRect = targetImg.getBoundingClientRect() const targetCenterY = targetRect.top + targetRect.height / 2 - + // 检查是否与目标图片重叠,使用更精确的碰撞检测 // 当拖拽图片覆盖目标图片高度的60%时触发排序 const overlapThreshold = targetRect.height * 0.6 const distance = Math.abs(draggedCenterY - targetCenterY) - + if (distance < overlapThreshold) { // 直接交换位置,移除视觉反馈以避免闪烁 swapImages(draggedImg, targetImg) @@ -1378,42 +1359,42 @@ const swapImages = (img1, img2) => { // 为交换添加平滑过渡效果 const parent1 = img1.parentNode const parent2 = img2.parentNode - + // 添加交换动画类 img1.classList.add('swap-animation') img2.classList.add('swap-animation') - + // 如果两张图片在同一父元素中 if (parent1 === parent2) { // 计算两个图片的位置差 const rect1 = img1.getBoundingClientRect() const rect2 = img2.getBoundingClientRect() const deltaY = rect2.top - rect1.top - + // 添加临时的变换动画 img1.style.transform = `translateY(${deltaY}px)` img2.style.transform = `translateY(${-deltaY}px)` - + // 在动画完成后交换DOM位置 setTimeout(() => { // 移除临时变换 img1.style.transform = '' img2.style.transform = '' - + // 移除交换动画类 img1.classList.remove('swap-animation') img2.classList.remove('swap-animation') - + // 交换DOM位置 const tempMarker = document.createElement('div') parent1.insertBefore(tempMarker, img1) parent1.insertBefore(img1, img2) parent1.insertBefore(img2, tempMarker) tempMarker.remove() - + // 触发内容更新 handleInput() - + // 自动退出排序模式,提高响应速度 setTimeout(() => { resetDragState() @@ -1425,16 +1406,16 @@ const swapImages = (img1, img2) => { // 移除交换动画类 img1.classList.remove('swap-animation') img2.classList.remove('swap-animation') - + const temp = document.createElement('div') parent1.insertBefore(temp, img1) parent2.insertBefore(img1, img2) parent1.insertBefore(img2, temp) temp.remove() - + // 触发内容更新 handleInput() - + // 自动退出排序模式,提高响应速度 setTimeout(() => { resetDragState() @@ -1464,16 +1445,16 @@ const updateToolbarState = () => { // 处理视口大小变化(用于检测虚拟键盘) const handleViewportResize = () => { if (!window.visualViewport) return - + const currentHeight = window.visualViewport.height const heightDifference = initialViewportHeight.value - currentHeight - + // 如果高度差超过150px,认为虚拟键盘已弹出 isKeyboardVisible.value = heightDifference > 150 - + // 动态设置CSS变量以调整工具栏位置 document.documentElement.style.setProperty('--viewport-height', `${currentHeight}px`) - + // 根据虚拟键盘状态更新工具栏可见性 updateToolbarVisibility() } @@ -1482,10 +1463,10 @@ const handleViewportResize = () => { const handleWindowResize = () => { const currentHeight = window.innerHeight const heightDifference = initialViewportHeight.value - currentHeight - + // 如果高度差超过150px,认为虚拟键盘已弹出 isKeyboardVisible.value = heightDifference > 150 - + // 根据虚拟键盘状态更新工具栏可见性 updateToolbarVisibility() } @@ -1518,7 +1499,7 @@ const isTodoContentActive = () => { } // 监听虚拟键盘状态变化 -watch(isKeyboardVisible, (newVal) => { +watch(isKeyboardVisible, newVal => { updateToolbarVisibility() }) @@ -1571,7 +1552,7 @@ const handleToolClick = (action, event) => { // 对于待办事项,确保工具栏保持可见 isToolbarVisible.value = true } - + // 确保工具栏在虚拟键盘可见时保持显示 if (isKeyboardVisible.value) { isToolbarVisible.value = true @@ -1613,229 +1594,216 @@ const handleToolbarFocusOut = () => { // 包装孤立的图片(没有被.image-container包装的图片) const wrapOrphanedImages = () => { - if (!editorRef.value) return; - + if (!editorRef.value) return + // 查找所有没有被.image-container包装的图片 - const images = editorRef.value.querySelectorAll('img:not(.editor-image)'); - console.log('Found orphaned images:', images.length); - + const images = editorRef.value.querySelectorAll('img:not(.editor-image)') + console.log('Found orphaned images:', images.length) + images.forEach(img => { // 检查图片是否已经在.image-container中 - if (img.closest('.image-container')) return; - - console.log('Wrapping orphaned image'); - + if (img.closest('.image-container')) return + + console.log('Wrapping orphaned image') + // 检查图片的父元素是否是.image-container,避免嵌套 if (img.parentNode && img.parentNode.classList && img.parentNode.classList.contains('image-container')) { - console.log('Image is already in image-container, checking for delete button'); + console.log('Image is already in image-container, checking for delete button') // 确保图片有正确的类名 - img.className = 'editor-image'; - img.setAttribute('data-draggable', 'true'); - + img.className = 'editor-image' + img.setAttribute('data-draggable', 'true') + // 为已存在的图片容器添加删除按钮事件监听器 - const imgContainer = img.parentNode; - const deleteBtn = imgContainer.querySelector('.image-delete-btn'); + const imgContainer = img.parentNode + const deleteBtn = imgContainer.querySelector('.image-delete-btn') if (deleteBtn) { - console.log('Found existing delete button, adding event listeners'); + console.log('Found existing delete button, adding event listeners') // 先移除可能已有的事件监听器,避免重复 - deleteBtn.removeEventListener('click', null); - deleteBtn.removeEventListener('touchend', null); - - deleteBtn.addEventListener('click', function(e) { - e.stopPropagation(); - imgContainer.remove(); - handleInput(); - }); - - deleteBtn.addEventListener('touchend', function(e) { - e.stopPropagation(); - imgContainer.remove(); - handleInput(); - }); - + deleteBtn.removeEventListener('click', null) + deleteBtn.removeEventListener('touchend', null) + + deleteBtn.addEventListener('click', function (e) { + e.stopPropagation() + imgContainer.remove() + handleInput() + }) + + deleteBtn.addEventListener('touchend', function (e) { + e.stopPropagation() + imgContainer.remove() + handleInput() + }) + // 为图片容器添加短按事件以显示/隐藏删除按钮 // 先移除可能已有的事件监听器,避免重复 - const touchStartHandler = imgContainer._touchStartHandler; - const touchEndHandler = imgContainer._touchEndHandler; - + const touchStartHandler = imgContainer._touchStartHandler + const touchEndHandler = imgContainer._touchEndHandler + if (touchStartHandler) { - imgContainer.removeEventListener('touchstart', touchStartHandler); + imgContainer.removeEventListener('touchstart', touchStartHandler) } - + if (touchEndHandler) { - imgContainer.removeEventListener('touchend', touchEndHandler); + imgContainer.removeEventListener('touchend', touchEndHandler) } - - let touchStartTime = 0; - const newTouchStartHandler = function(e) { - touchStartTime = Date.now(); - }; - - const newTouchEndHandler = function(e) { - const touchDuration = Date.now() - touchStartTime; - console.log('Touch end event triggered for existing image, duration:', touchDuration, 'isLongPress:', dragState.value.isLongPress); + + let touchStartTime = 0 + const newTouchStartHandler = function (e) { + touchStartTime = Date.now() + } + + const newTouchEndHandler = function (e) { + const touchDuration = Date.now() - touchStartTime + console.log('Touch end event triggered for existing image, duration:', touchDuration, 'isLongPress:', dragState.value.isLongPress) // 短按(小于200ms)且非长按拖拽状态时切换删除按钮显示 if (touchDuration < 200 && !dragState.value.isLongPress) { - e.stopPropagation(); - console.log('Short tap detected for existing image, toggling delete button visibility'); + e.stopPropagation() + console.log('Short tap detected for existing image, toggling delete button visibility') // 切换删除按钮的显示状态 if (deleteBtn) { - console.log('Current delete button display style for existing image:', deleteBtn.style.display); + console.log('Current delete button display style for existing image:', deleteBtn.style.display) // 检查删除按钮当前是否可见 - const computedStyle = getComputedStyle(deleteBtn); - const isCurrentlyVisible = deleteBtn.style.display === 'block' || - computedStyle.display === 'block' || - (deleteBtn.style.display !== 'none' && - computedStyle.display !== 'none'); - - console.log('Delete button current styles for existing image - inline:', deleteBtn.style.display, 'computed:', computedStyle.display); - + const isCurrentlyVisible = deleteBtn.classList.contains('visible') + + console.log('Delete button current styles for existing image - inline:', deleteBtn.style.display) + if (isCurrentlyVisible) { - deleteBtn.style.display = 'none'; - console.log('Delete button hidden for existing image'); + deleteBtn.classList.remove('visible') + console.log('Delete button hidden for existing image') } else { - deleteBtn.style.display = 'block'; - console.log('Delete button displayed for existing image'); + deleteBtn.classList.add('visible') + console.log('Delete button displayed for existing image') } } else { - console.log('Delete button not found for existing image'); + console.log('Delete button not found for existing image') } } else { - console.log('Not a short tap or isLongPress is true for existing image'); + console.log('Not a short tap or isLongPress is true for existing image') } - }; - - imgContainer.addEventListener('touchstart', newTouchStartHandler); - imgContainer.addEventListener('touchend', newTouchEndHandler); - + } + + imgContainer.addEventListener('touchstart', newTouchStartHandler) + imgContainer.addEventListener('touchend', newTouchEndHandler) + // 保存事件处理函数的引用,以便后续移除 - imgContainer._touchStartHandler = newTouchStartHandler; - imgContainer._touchEndHandler = newTouchEndHandler; + imgContainer._touchStartHandler = newTouchStartHandler + imgContainer._touchEndHandler = newTouchEndHandler } - return; + return } - + // 创建图片容器 - const imgContainer = document.createElement('div'); - imgContainer.className = 'image-container'; - imgContainer.style.position = 'relative'; - imgContainer.style.display = 'inline-block'; - + const imgContainer = document.createElement('div') + imgContainer.className = 'image-container' + imgContainer.style.position = 'relative' + imgContainer.style.display = 'inline-block' + // 设置图片样式 - img.className = 'editor-image'; - img.setAttribute('data-draggable', 'true'); - img.style.maxWidth = '100%'; - img.style.height = 'auto'; - img.style.display = 'block'; - img.style.objectFit = 'cover'; - img.style.boxSizing = 'border-box'; - img.style.border = '0.625rem solid white'; - img.style.borderRadius = '0.2rem'; - img.style.boxShadow = '0 1px 5px rgba(0, 0, 0, 0.18)'; - img.style.background = 'var(--background-secondary)'; - img.style.position = 'relative'; - img.style.outline = 'none'; - img.style.userSelect = 'none'; // 防止选中 - img.style.webkitUserSelect = 'none'; // 防止选中 - img.style.mozUserSelect = 'none'; // 防止选中 - img.style.msUserSelect = 'none'; // 防止选中 - img.style.webkitTouchCallout = 'none'; // 防止长按弹出菜单 - img.style.webkitTapHighlightColor = 'transparent'; // 防止点击高亮 - img.draggable = true; - + img.className = 'editor-image' + img.setAttribute('data-draggable', 'true') + img.style.maxWidth = '100%' + img.style.height = 'auto' + img.style.display = 'block' + img.style.objectFit = 'cover' + img.style.boxSizing = 'border-box' + img.style.border = '0.625rem solid white' + img.style.borderRadius = '0.2rem' + img.style.boxShadow = '0 1px 5px rgba(0, 0, 0, 0.18)' + img.style.background = 'var(--background-secondary)' + img.style.position = 'relative' + img.style.outline = 'none' + img.style.userSelect = 'none' // 防止选中 + img.style.webkitUserSelect = 'none' // 防止选中 + img.style.mozUserSelect = 'none' // 防止选中 + img.style.msUserSelect = 'none' // 防止选中 + img.style.webkitTouchCallout = 'none' // 防止长按弹出菜单 + img.style.webkitTapHighlightColor = 'transparent' // 防止点击高亮 + img.draggable = true + // 创建删除按钮 - const deleteBtn = document.createElement('div'); - deleteBtn.className = 'image-delete-btn'; - deleteBtn.style.cssText = 'position: absolute; top: 8px; right: 8px; width: 24px; height: 24px; cursor: pointer; z-index: 1000; display: none; transition: opacity 0.2s ease; touch-action: manipulation;'; - + const deleteBtn = document.createElement('div') + deleteBtn.className = 'image-delete-btn' + // 将图片和删除按钮添加到容器中 - imgContainer.appendChild(img); - imgContainer.appendChild(deleteBtn); - + imgContainer.appendChild(img) + imgContainer.appendChild(deleteBtn) + // 替换原来的图片 - img.parentNode.replaceChild(imgContainer, img); - + img.parentNode.replaceChild(imgContainer, img) + // 为新包装的图片添加事件监听器 // 先移除可能已有的事件监听器,避免重复 imgContainer.removeEventListener('touchstart', handleTouchStart) imgContainer.removeEventListener('touchmove', handleTouchMove) imgContainer.removeEventListener('touchend', handleTouchEnd) imgContainer.removeEventListener('touchcancel', handleTouchCancel) - + // 重新添加事件监听器 imgContainer.addEventListener('touchstart', handleTouchStart) imgContainer.addEventListener('touchmove', handleTouchMove) imgContainer.addEventListener('touchend', handleTouchEnd) imgContainer.addEventListener('touchcancel', handleTouchCancel) - + // 为删除按钮添加点击事件 // 先移除可能已有的事件监听器,避免重复 deleteBtn.removeEventListener('click', null) deleteBtn.removeEventListener('touchend', null) - - deleteBtn.addEventListener('click', function(e) { - e.stopPropagation(); - imgContainer.remove(); - handleInput(); - }); - - deleteBtn.addEventListener('touchend', function(e) { - e.stopPropagation(); - imgContainer.remove(); - handleInput(); - }); - + + deleteBtn.addEventListener('click', function (e) { + e.stopPropagation() + imgContainer.remove() + handleInput() + }) + + deleteBtn.addEventListener('touchend', function (e) { + e.stopPropagation() + imgContainer.remove() + handleInput() + }) + // 为图片容器添加短按事件以显示/隐藏删除按钮 - let touchStartTime = 0; - const touchStartHandler = function(e) { - touchStartTime = Date.now(); - }; - - const touchEndHandler = function(e) { - const touchDuration = Date.now() - touchStartTime; - console.log('Touch end event triggered in wrapOrphanedImages, duration:', touchDuration, 'isLongPress:', dragState.value.isLongPress); + let touchStartTime = 0 + const touchStartHandler = function (e) { + touchStartTime = Date.now() + } + + const touchEndHandler = function (e) { + const touchDuration = Date.now() - touchStartTime + console.log('Touch end event triggered in wrapOrphanedImages, duration:', touchDuration, 'isLongPress:', dragState.value.isLongPress) // 短按(小于200ms)且非长按拖拽状态时切换删除按钮显示 if (touchDuration < 200 && !dragState.value.isLongPress) { - e.stopPropagation(); - console.log('Short tap detected in wrapOrphanedImages, toggling delete button visibility'); + e.stopPropagation() + console.log('Short tap detected in wrapOrphanedImages, toggling delete button visibility') // 切换删除按钮的显示状态 if (deleteBtn) { - console.log('Current delete button display style in wrapOrphanedImages:', deleteBtn.style.display); + console.log('Current delete button display style in wrapOrphanedImages:', deleteBtn.style.display) // 检查删除按钮当前是否可见 - const computedStyle = getComputedStyle(deleteBtn); - const isCurrentlyVisible = deleteBtn.style.display === 'block' || - computedStyle.display === 'block' || - (deleteBtn.style.display !== 'none' && - computedStyle.display !== 'none'); - - console.log('Delete button current styles - inline:', deleteBtn.style.display, 'computed:', computedStyle.display); - console.log('Delete button background image:', computedStyle.backgroundImage); - console.log('Delete button width:', computedStyle.width, 'height:', computedStyle.height); - console.log('Delete button position:', computedStyle.position); - console.log('Delete button z-index:', computedStyle.zIndex); - + const isCurrentlyVisible = deleteBtn.classList.contains('visible') + + console.log('Delete button current styles - inline:', deleteBtn.style.display) + if (isCurrentlyVisible) { - deleteBtn.style.display = 'none'; - console.log('Delete button hidden in wrapOrphanedImages'); + deleteBtn.classList.remove('visible') + console.log('Delete button hidden in wrapOrphanedImages') } else { - deleteBtn.style.display = 'block'; - console.log('Delete button displayed in wrapOrphanedImages'); + deleteBtn.classList.add('visible') + console.log('Delete button displayed in wrapOrphanedImages') } } else { - console.log('Delete button not found in wrapOrphanedImages'); + console.log('Delete button not found in wrapOrphanedImages') } } else { - console.log('Not a short tap or isLongPress is true in wrapOrphanedImages'); + console.log('Not a short tap or isLongPress is true in wrapOrphanedImages') } - }; - - imgContainer.addEventListener('touchstart', touchStartHandler); - imgContainer.addEventListener('touchend', touchEndHandler); - + } + + imgContainer.addEventListener('touchstart', touchStartHandler) + imgContainer.addEventListener('touchend', touchEndHandler) + // 保存事件处理函数的引用,以便后续移除 - imgContainer._touchStartHandler = touchStartHandler; - imgContainer._touchEndHandler = touchEndHandler; - }); + imgContainer._touchStartHandler = touchStartHandler + imgContainer._touchEndHandler = touchEndHandler + }) } // 调整已有图片的高度 @@ -1849,7 +1817,7 @@ const adjustExistingImages = () => { imageContainers.forEach(container => { const img = container.querySelector('img.editor-image') if (!img) return - + console.log('Processing image:', img) // 只处理还没有调整过高度的图片 if (!img.dataset.heightAdjusted) { @@ -1895,12 +1863,12 @@ const adjustExistingImages = () => { tempImg.src = img.src } }) - + // 为现有图片添加拖拽功能和删除按钮功能 imageContainers.forEach(container => { const img = container.querySelector('img.editor-image') if (!img) return - + console.log('Adding drag functionality to image:', img) // 为图片容器添加事件监听器(总是添加,确保功能正常) // 先移除可能已有的事件监听器,避免重复 @@ -1908,13 +1876,13 @@ const adjustExistingImages = () => { container.removeEventListener('touchmove', handleTouchMove) container.removeEventListener('touchend', handleTouchEnd) container.removeEventListener('touchcancel', handleTouchCancel) - + // 重新添加事件监听器 container.addEventListener('touchstart', handleTouchStart) container.addEventListener('touchmove', handleTouchMove) container.addEventListener('touchend', handleTouchEnd) container.addEventListener('touchcancel', handleTouchCancel) - + // 为删除按钮添加点击事件 let deleteBtn = container.querySelector('.image-delete-btn') if (!deleteBtn) { @@ -1922,87 +1890,82 @@ const adjustExistingImages = () => { console.log('Delete button not found, creating new one') deleteBtn = document.createElement('div') deleteBtn.className = 'image-delete-btn' - deleteBtn.style.cssText = 'position: absolute; top: 8px; right: 8px; width: 24px; height: 24px; cursor: pointer; z-index: 1000; display: none; transition: opacity 0.2s ease; touch-action: manipulation;' container.appendChild(deleteBtn) } - + if (deleteBtn) { // 先移除可能已有的事件监听器,避免重复 deleteBtn.removeEventListener('click', null) deleteBtn.removeEventListener('touchend', null) - - deleteBtn.addEventListener('click', function(e) { - e.stopPropagation(); - container.remove(); - handleInput(); - }); - - deleteBtn.addEventListener('touchend', function(e) { - e.stopPropagation(); - container.remove(); - handleInput(); - }); + + deleteBtn.addEventListener('click', function (e) { + e.stopPropagation() + container.remove() + handleInput() + }) + + deleteBtn.addEventListener('touchend', function (e) { + e.stopPropagation() + container.remove() + handleInput() + }) } - + // 为图片容器添加短按事件以显示/隐藏删除按钮 // 先移除可能已有的事件监听器,避免重复 - const touchStartHandler = container._touchStartHandler; - const touchEndHandler = container._touchEndHandler; - + const touchStartHandler = container._touchStartHandler + const touchEndHandler = container._touchEndHandler + if (touchStartHandler) { - container.removeEventListener('touchstart', touchStartHandler); + container.removeEventListener('touchstart', touchStartHandler) } - + if (touchEndHandler) { - container.removeEventListener('touchend', touchEndHandler); + container.removeEventListener('touchend', touchEndHandler) } - - let touchStartTime = 0; - const newTouchStartHandler = function(e) { - touchStartTime = Date.now(); - }; - - const newTouchEndHandler = function(e) { - const touchDuration = Date.now() - touchStartTime; - console.log('Touch end event triggered in adjustExistingImages, duration:', touchDuration, 'isLongPress:', dragState.value.isLongPress); + + let touchStartTime = 0 + const newTouchStartHandler = function (e) { + touchStartTime = Date.now() + } + + const newTouchEndHandler = function (e) { + const touchDuration = Date.now() - touchStartTime + console.log('Touch end event triggered in adjustExistingImages, duration:', touchDuration, 'isLongPress:', dragState.value.isLongPress) // 短按(小于200ms)且非长按拖拽状态时切换删除按钮显示 if (touchDuration < 200 && !dragState.value.isLongPress) { - e.stopPropagation(); - console.log('Short tap detected in adjustExistingImages, toggling delete button visibility'); + e.stopPropagation() + console.log('Short tap detected in adjustExistingImages, toggling delete button visibility') // 切换删除按钮的显示状态 if (deleteBtn) { - console.log('Current delete button display style in adjustExistingImages:', deleteBtn.style.display); + console.log('Current delete button display style in adjustExistingImages:', deleteBtn.style.display) // 检查删除按钮当前是否可见 - const computedStyle = getComputedStyle(deleteBtn); - const isCurrentlyVisible = deleteBtn.style.display === 'block' || - computedStyle.display === 'block' || - (deleteBtn.style.display !== 'none' && - computedStyle.display !== 'none'); - - console.log('Delete button current styles - inline:', deleteBtn.style.display, 'computed:', computedStyle.display); - + const isCurrentlyVisible = deleteBtn.classList.contains('visible') + + console.log('Delete button current styles - inline:', deleteBtn.style.display) + if (isCurrentlyVisible) { - deleteBtn.style.display = 'none'; - console.log('Delete button hidden in adjustExistingImages'); + deleteBtn.classList.remove('visible') + console.log('Delete button hidden in adjustExistingImages') } else { - deleteBtn.style.display = 'block'; - console.log('Delete button displayed in adjustExistingImages'); + deleteBtn.classList.add('visible') + console.log('Delete button displayed in adjustExistingImages') } } else { - console.log('Delete button not found in adjustExistingImages'); + console.log('Delete button not found in adjustExistingImages') } } else { - console.log('Not a short tap or isLongPress is true in adjustExistingImages'); + console.log('Not a short tap or isLongPress is true in adjustExistingImages') } - }; - - container.addEventListener('touchstart', newTouchStartHandler); - container.addEventListener('touchend', newTouchEndHandler); - + } + + container.addEventListener('touchstart', newTouchStartHandler) + container.addEventListener('touchend', newTouchEndHandler) + // 保存事件处理函数的引用,以便后续移除 - container._touchStartHandler = newTouchStartHandler; - container._touchEndHandler = newTouchEndHandler; - + container._touchStartHandler = newTouchStartHandler + container._touchEndHandler = newTouchEndHandler + img.setAttribute('data-touch-listeners', 'true') console.log('Added touch event listeners') }) @@ -2012,38 +1975,44 @@ const adjustExistingImages = () => { // 清理动态添加的属性(仅在保存时移除临时属性,保留必要属性) const cleanContentForSave = () => { - if (!editorRef.value) return content.value; - + if (!editorRef.value) return content.value + // 创建一个临时的div来操作内容 - const tempDiv = document.createElement('div'); - tempDiv.innerHTML = editorRef.value.innerHTML; - + const tempDiv = document.createElement('div') + tempDiv.innerHTML = editorRef.value.innerHTML + // 移除图片上的临时动态属性 - const images = tempDiv.querySelectorAll('img.editor-image'); + const images = tempDiv.querySelectorAll('img.editor-image') images.forEach(img => { // 移除拖拽时的临时样式属性 - img.style.removeProperty('z-index'); - img.style.removeProperty('transition'); - img.style.removeProperty('transform'); - img.style.removeProperty('opacity'); - + img.style.removeProperty('z-index') + img.style.removeProperty('transition') + img.style.removeProperty('transform') + img.style.removeProperty('opacity') + // 移除拖拽时的临时类名 - img.classList.remove('dragging'); - img.classList.remove('swap-animation'); - + img.classList.remove('dragging') + img.classList.remove('swap-animation') + // 移除临时的数据属性(保留必要的属性如data-draggable) - img.removeAttribute('data-height-adjusted'); - img.removeAttribute('data-touch-listeners'); - }); - + img.removeAttribute('data-height-adjusted') + img.removeAttribute('data-touch-listeners') + }) + + // 移除删除按钮的显示状态类 + const deleteButtons = tempDiv.querySelectorAll('.image-delete-btn') + deleteButtons.forEach(btn => { + btn.classList.remove('visible') + }) + // 移除拖拽指示器(如果存在) - const indicators = tempDiv.querySelectorAll('.drag-indicator'); + const indicators = tempDiv.querySelectorAll('.drag-indicator') indicators.forEach(indicator => { - indicator.remove(); - }); - - return tempDiv.innerHTML; -}; + indicator.remove() + }) + + return tempDiv.innerHTML +} // 暴露方法给父组件 defineExpose({ @@ -2073,105 +2042,100 @@ defineExpose({ imageContainers.forEach(container => { const img = container.querySelector('img.editor-image') if (!img) return - + console.log('Adding touch listeners to image in setContent:', img) // 先移除可能已有的事件监听器,避免重复 container.removeEventListener('touchstart', handleTouchStart) container.removeEventListener('touchmove', handleTouchMove) container.removeEventListener('touchend', handleTouchEnd) container.removeEventListener('touchcancel', handleTouchCancel) - + // 重新添加事件监听器 container.addEventListener('touchstart', handleTouchStart) container.addEventListener('touchmove', handleTouchMove) container.addEventListener('touchend', handleTouchEnd) container.addEventListener('touchcancel', handleTouchCancel) - + // 为删除按钮添加点击事件 const deleteBtn = container.querySelector('.image-delete-btn') if (deleteBtn) { // 先移除可能已有的事件监听器,避免重复 deleteBtn.removeEventListener('click', null) deleteBtn.removeEventListener('touchend', null) - - deleteBtn.addEventListener('click', function(e) { - e.stopPropagation(); - container.remove(); - handleInput(); - }); - - deleteBtn.addEventListener('touchend', function(e) { - e.stopPropagation(); - container.remove(); - handleInput(); - }); + + deleteBtn.addEventListener('click', function (e) { + e.stopPropagation() + container.remove() + handleInput() + }) + + deleteBtn.addEventListener('touchend', function (e) { + e.stopPropagation() + container.remove() + handleInput() + }) } - + // 为图片容器添加短按事件以显示/隐藏删除按钮 // 先移除可能已有的事件监听器,避免重复 - const touchStartHandler = container._touchStartHandler; - const touchEndHandler = container._touchEndHandler; - + const touchStartHandler = container._touchStartHandler + const touchEndHandler = container._touchEndHandler + if (touchStartHandler) { - container.removeEventListener('touchstart', touchStartHandler); + container.removeEventListener('touchstart', touchStartHandler) } - + if (touchEndHandler) { - container.removeEventListener('touchend', touchEndHandler); + container.removeEventListener('touchend', touchEndHandler) } - - let touchStartTime = 0; - const newTouchStartHandler = function(e) { - touchStartTime = Date.now(); - }; - - const newTouchEndHandler = function(e) { - const touchDuration = Date.now() - touchStartTime; - console.log('Touch end event triggered in setContent, duration:', touchDuration, 'isLongPress:', dragState.value.isLongPress); + + let touchStartTime = 0 + const newTouchStartHandler = function (e) { + touchStartTime = Date.now() + } + + const newTouchEndHandler = function (e) { + const touchDuration = Date.now() - touchStartTime + console.log('Touch end event triggered in setContent, duration:', touchDuration, 'isLongPress:', dragState.value.isLongPress) // 短按(小于200ms)且非长按拖拽状态时切换删除按钮显示 if (touchDuration < 200 && !dragState.value.isLongPress) { - e.stopPropagation(); - console.log('Short tap detected in setContent, toggling delete button visibility'); + e.stopPropagation() + console.log('Short tap detected in setContent, toggling delete button visibility') // 切换删除按钮的显示状态 if (deleteBtn) { - console.log('Current delete button display style in setContent:', deleteBtn.style.display); + console.log('Current delete button display style in setContent:', deleteBtn.style.display) // 检查删除按钮当前是否可见 - const computedStyle = getComputedStyle(deleteBtn); - const isCurrentlyVisible = deleteBtn.style.display === 'block' || - computedStyle.display === 'block' || - (deleteBtn.style.display !== 'none' && - computedStyle.display !== 'none'); - - console.log('Delete button current styles - inline:', deleteBtn.style.display, 'computed:', computedStyle.display); - console.log('Delete button background image:', computedStyle.backgroundImage); - console.log('Delete button width:', computedStyle.width, 'height:', computedStyle.height); - console.log('Delete button position:', computedStyle.position); - console.log('Delete button z-index:', computedStyle.zIndex); - + const computedStyle = getComputedStyle(deleteBtn) + const isCurrentlyVisible = deleteBtn.classList.contains('visible') + + console.log('Delete button current styles - inline:', deleteBtn.style.display, 'computed:', computedStyle.display) + console.log('Delete button background image:', computedStyle.backgroundImage) + console.log('Delete button width:', computedStyle.width, 'height:', computedStyle.height) + console.log('Delete button position:', computedStyle.position) + console.log('Delete button z-index:', computedStyle.zIndex) + if (isCurrentlyVisible) { - deleteBtn.style.display = 'none'; - console.log('Delete button hidden in setContent'); + deleteBtn.classList.remove('visible') + console.log('Delete button hidden in setContent') } else { - deleteBtn.style.display = 'block'; - console.log('Delete button displayed in setContent'); - // 添加调试样式以确保可见 - deleteBtn.style.backgroundColor = 'rgba(255, 0, 0, 0.3)'; // 半透明红色背景用于调试 + deleteBtn.classList.add('visible') + console.log('Delete button displayed in setContent') } } else { - console.log('Delete button not found in setContent'); + console.log('Delete button not found in setContent') } } else { - console.log('Not a short tap or isLongPress is true in setContent'); + console.log('Not a short tap or isLongPress is true in setContent') } - }; - - container.addEventListener('touchstart', newTouchStartHandler); - container.addEventListener('touchend', newTouchEndHandler); - + } + + container.addEventListener('touchstart', newTouchStartHandler) + container.addEventListener('touchend', newTouchEndHandler) + // 保存事件处理函数的引用,以便后续移除 - container._touchStartHandler = newTouchStartHandler; - container._touchEndHandler = newTouchEndHandler; - + container._touchStartHandler = newTouchStartHandler + container._touchEndHandler = newTouchEndHandler + img.setAttribute('data-touch-listeners', 'true') console.log('Added touch event listeners') }) @@ -2212,99 +2176,95 @@ defineExpose({ imageContainers.forEach(container => { const img = container.querySelector('img.editor-image') if (!img) return - + console.log('Adding touch listeners to image in delayed setContent:', img) // 先移除可能已有的事件监听器,避免重复 container.removeEventListener('touchstart', handleTouchStart) container.removeEventListener('touchmove', handleTouchMove) container.removeEventListener('touchend', handleTouchEnd) container.removeEventListener('touchcancel', handleTouchCancel) - + // 重新添加事件监听器 container.addEventListener('touchstart', handleTouchStart) container.addEventListener('touchmove', handleTouchMove) container.addEventListener('touchend', handleTouchEnd) container.addEventListener('touchcancel', handleTouchCancel) - + // 为删除按钮添加点击事件 const deleteBtn = container.querySelector('.image-delete-btn') if (deleteBtn) { // 先移除可能已有的事件监听器,避免重复 deleteBtn.removeEventListener('click', null) deleteBtn.removeEventListener('touchend', null) - - deleteBtn.addEventListener('click', function(e) { - e.stopPropagation(); - container.remove(); - handleInput(); - }); - - deleteBtn.addEventListener('touchend', function(e) { - e.stopPropagation(); - container.remove(); - handleInput(); - }); + + deleteBtn.addEventListener('click', function (e) { + e.stopPropagation() + container.remove() + handleInput() + }) + + deleteBtn.addEventListener('touchend', function (e) { + e.stopPropagation() + container.remove() + handleInput() + }) } - + // 为图片容器添加短按事件以显示/隐藏删除按钮 // 先移除可能已有的事件监听器,避免重复 - const touchStartHandler = container._touchStartHandler; - const touchEndHandler = container._touchEndHandler; - + const touchStartHandler = container._touchStartHandler + const touchEndHandler = container._touchEndHandler + if (touchStartHandler) { - container.removeEventListener('touchstart', touchStartHandler); + container.removeEventListener('touchstart', touchStartHandler) } - + if (touchEndHandler) { - container.removeEventListener('touchend', touchEndHandler); + container.removeEventListener('touchend', touchEndHandler) } - - let touchStartTime = 0; - const newTouchStartHandler = function(e) { - touchStartTime = Date.now(); - }; - - const newTouchEndHandler = function(e) { - const touchDuration = Date.now() - touchStartTime; - console.log('Touch end event triggered in delayed setContent, duration:', touchDuration, 'isLongPress:', dragState.value.isLongPress); + + let touchStartTime = 0 + const newTouchStartHandler = function (e) { + touchStartTime = Date.now() + } + + const newTouchEndHandler = function (e) { + const touchDuration = Date.now() - touchStartTime + console.log('Touch end event triggered in delayed setContent, duration:', touchDuration, 'isLongPress:', dragState.value.isLongPress) // 短按(小于200ms)且非长按拖拽状态时切换删除按钮显示 if (touchDuration < 200 && !dragState.value.isLongPress) { - e.stopPropagation(); - console.log('Short tap detected in delayed setContent, toggling delete button visibility'); + e.stopPropagation() + console.log('Short tap detected in delayed setContent, toggling delete按钮visibility') // 切换删除按钮的显示状态 if (deleteBtn) { - console.log('Current delete button display style in delayed setContent:', deleteBtn.style.display); + console.log('Current delete button display style in delayed setContent:', deleteBtn.style.display) // 检查删除按钮当前是否可见 - const computedStyle = getComputedStyle(deleteBtn); - const isCurrentlyVisible = deleteBtn.style.display === 'block' || - computedStyle.display === 'block' || - (deleteBtn.style.display !== 'none' && - computedStyle.display !== 'none'); - - console.log('Delete button current styles - inline:', deleteBtn.style.display, 'computed:', computedStyle.display); - + const isCurrentlyVisible = deleteBtn.classList.contains('visible') + + console.log('Delete button current styles - inline:', deleteBtn.style.display, 'computed:', computedStyle.display) + if (isCurrentlyVisible) { - deleteBtn.style.display = 'none'; - console.log('Delete button hidden in delayed setContent'); + deleteBtn.classList.remove('visible') + console.log('Delete button hidden in delayed setContent') } else { - deleteBtn.style.display = 'block'; - console.log('Delete button displayed in delayed setContent'); + deleteBtn.classList.add('visible') + console.log('Delete button displayed in delayed setContent') } } else { - console.log('Delete button not found in delayed setContent'); + console.log('Delete button not found in delayed setContent') } } else { - console.log('Not a short tap or isLongPress is true in delayed setContent'); + console.log('Not a short tap or isLongPress is true in delayed setContent') } - }; - - container.addEventListener('touchstart', newTouchStartHandler); - container.addEventListener('touchend', newTouchEndHandler); - + } + + container.addEventListener('touchstart', newTouchStartHandler) + container.addEventListener('touchend', newTouchEndHandler) + // 保存事件处理函数的引用,以便后续移除 - container._touchStartHandler = newTouchStartHandler; - container._touchEndHandler = newTouchEndHandler; - + container._touchStartHandler = newTouchStartHandler + container._touchEndHandler = newTouchEndHandler + img.setAttribute('data-touch-listeners', 'true') console.log('Added touch event listeners') }) @@ -2560,7 +2520,6 @@ defineExpose({ height: 24px; cursor: pointer; z-index: 1000; - display: none; transition: opacity 0.2s ease; /* 使用背景图片而不是背景色和边框,确保图标正确显示 */ background-image: url('/assets/icons/drawable-xxhdpi/item_image_btn_unbrella_delete.png'); @@ -2568,6 +2527,13 @@ defineExpose({ background-repeat: no-repeat; background-position: center; background-color: transparent; /* 确保背景透明 */ + pointer-events: none; + opacity: 0; +} + +:deep(.editor-content .image-delete-btn.visible) { + pointer-events: all; + opacity: 1; } :deep(.editor-content .editor-image.draggable) {