From 4e2771277de812e365532b98d10265d7ca689fc0 Mon Sep 17 00:00:00 2001 From: yuantao Date: Thu, 16 Oct 2025 10:35:50 +0800 Subject: [PATCH] =?UTF-8?q?\"feat:=20=E4=B8=BA=E5=9B=BE=E7=89=87=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E7=A7=BB=E9=99=A4=E6=8C=89=E9=92=AE=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E7=94=A8item=5Fimage=5Fbtn=5Funbrella=5Fdelete.png=E5=9B=BE?= =?UTF-8?q?=E6=A0=87\"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/RichTextEditor.vue | 204 +++++++++++++++++++++++------- 1 file changed, 156 insertions(+), 48 deletions(-) diff --git a/src/components/RichTextEditor.vue b/src/components/RichTextEditor.vue index d89b6c6..0893e8d 100644 --- a/src/components/RichTextEditor.vue +++ b/src/components/RichTextEditor.vue @@ -684,6 +684,12 @@ const insertImage = () => { const range = selection.getRangeAt(0) console.log('Current range:', range) + // 创建图片容器 + const imgContainer = document.createElement('div') + imgContainer.className = 'image-container' + imgContainer.style.position = 'relative' + imgContainer.style.display = 'inline-block' + // 创建图片元素 const img = document.createElement('img') img.src = imageDataUrl @@ -702,6 +708,24 @@ const insertImage = () => { img.style.outline = 'none' // 移除默认焦点轮廓 img.draggable = true + // 创建删除按钮 + const deleteBtn = document.createElement('img') + deleteBtn.src = '/assets/icons/drawable-xxhdpi/item_image_btn_unbrella_delete.png' + deleteBtn.className = 'image-delete-btn' + deleteBtn.style.position = 'absolute' + deleteBtn.style.top = '8px' + deleteBtn.style.right = '8px' + deleteBtn.style.width = '24px' + deleteBtn.style.height = '24px' + deleteBtn.style.cursor = 'pointer' + deleteBtn.style.zIndex = '10' + deleteBtn.style.display = 'none' // 默认隐藏 + deleteBtn.style.transition = 'opacity 0.2s ease' + + // 将图片和删除按钮添加到容器中 + imgContainer.appendChild(img) + imgContainer.appendChild(deleteBtn) + console.log('Created image element:', img) // 创建一个临时图片来获取原始尺寸 @@ -746,20 +770,43 @@ const insertImage = () => { img.addEventListener('touchmove', handleTouchMove) img.addEventListener('touchend', handleTouchEnd) img.addEventListener('touchcancel', handleTouchCancel) + + // 为图片容器添加事件监听器 + imgContainer.addEventListener('touchstart', handleTouchStart) + imgContainer.addEventListener('touchmove', handleTouchMove) + imgContainer.addEventListener('touchend', handleTouchEnd) + imgContainer.addEventListener('touchcancel', handleTouchCancel) + + // 为删除按钮添加点击事件 + deleteBtn.addEventListener('click', function(e) { + e.stopPropagation(); + imgContainer.remove(); + handleInput(); + }); + + // 为图片容器添加鼠标悬停事件以显示/隐藏删除按钮 + imgContainer.addEventListener('mouseenter', function() { + deleteBtn.style.display = 'block'; + }); + + imgContainer.addEventListener('mouseleave', function() { + deleteBtn.style.display = 'none'; + }); + console.log('Added touch event listeners') - // 插入图片到当前光标位置 - range.insertNode(img) - console.log('Inserted image into editor') + // 插入图片容器到当前光标位置 + range.insertNode(imgContainer) + console.log('Inserted image container into editor') // 调试信息 - console.log('Image inserted:', img) - console.log('Next sibling (should be drag handle):', img.nextSibling) + console.log('Image container inserted:', imgContainer) + console.log('Next sibling (should be drag handle):', imgContainer.nextSibling) // 添加换行 const br = document.createElement('br') - img.parentNode.insertBefore(br, img.nextSibling) - console.log('Added line break after image') + imgContainer.parentNode.insertBefore(br, imgContainer.nextSibling) + console.log('Added line break after image container') // 触发输入事件更新内容 handleInput() @@ -1090,7 +1137,7 @@ const checkAndSwapImages = (draggedImg, deltaY) => { // 检查是否与目标图片重叠,使用更精确的碰撞检测 // 当拖拽图片覆盖目标图片高度的三分之二时触发排序 - const overlapThreshold = targetRect.height * 0.67 + const overlapThreshold = targetRect.height * 0.27 const distance = Math.abs(draggedCenterY - targetCenterY) if (distance < overlapThreshold) { @@ -1306,9 +1353,12 @@ const adjustExistingImages = () => { // 等待DOM更新完成 setTimeout(() => { if (editorRef.value) { - const imageElements = editorRef.value.querySelectorAll('img.editor-image') - console.log('Found image elements:', imageElements.length) - imageElements.forEach(img => { + const imageContainers = editorRef.value.querySelectorAll('.image-container') + console.log('Found image containers:', imageContainers.length) + imageContainers.forEach(container => { + const img = container.querySelector('img.editor-image') + if (!img) return + console.log('Processing image:', img) // 只处理还没有调整过高度的图片 if (!img.dataset.heightAdjusted) { @@ -1356,27 +1406,42 @@ const adjustExistingImages = () => { }) // 为现有图片添加拖拽功能 - imageElements.forEach(img => { + imageContainers.forEach(container => { + const img = container.querySelector('img.editor-image') + if (!img) return + console.log('Adding drag functionality to image:', img) // 添加触摸事件监听器 if (!img.hasAttribute('data-touch-listeners')) { console.log('Adding touch event listeners') - img.addEventListener('touchstart', handleTouchStart) - img.addEventListener('touchmove', handleTouchMove) - img.addEventListener('touchend', handleTouchEnd) - img.addEventListener('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.addEventListener('click', function(e) { + e.stopPropagation(); + container.remove(); + handleInput(); + }); + } + + // 为图片容器添加鼠标悬停事件以显示/隐藏删除按钮 + container.addEventListener('mouseenter', function() { + if (deleteBtn) deleteBtn.style.display = 'block'; + }); + + container.addEventListener('mouseleave', function() { + if (deleteBtn) deleteBtn.style.display = 'none'; + }); + img.setAttribute('data-touch-listeners', 'true') console.log('Added touch event listeners') } - - // 移除已存在的拖拽手柄 - setTimeout(() => { - const dragHandle = img.nextElementSibling - if (dragHandle && dragHandle.classList.contains('image-drag-handle')) { - console.log('Removing existing drag handle') - dragHandle.remove() - } - }, 0) }) } }, 0) @@ -1397,21 +1462,34 @@ defineExpose({ // 为图片添加拖拽事件监听器 setTimeout(() => { console.log('Adding drag event listeners to images in setContent') - const imageElements = editorRef.value.querySelectorAll('img.editor-image') - console.log('Found images in setContent:', imageElements.length) - imageElements.forEach(img => { + const imageContainers = editorRef.value.querySelectorAll('.image-container') + console.log('Found image containers in setContent:', imageContainers.length) + imageContainers.forEach(container => { + const img = container.querySelector('img.editor-image') + if (!img) return + console.log('Adding touch listeners to image in setContent:', img) // 先移除可能已有的事件监听器,避免重复 - img.removeEventListener('touchstart', handleTouchStart) - img.removeEventListener('touchmove', handleTouchMove) - img.removeEventListener('touchend', handleTouchEnd) - img.removeEventListener('touchcancel', handleTouchCancel) + container.removeEventListener('touchstart', handleTouchStart) + container.removeEventListener('touchmove', handleTouchMove) + container.removeEventListener('touchend', handleTouchEnd) + container.removeEventListener('touchcancel', handleTouchCancel) // 重新添加事件监听器 - img.addEventListener('touchstart', handleTouchStart) - img.addEventListener('touchmove', handleTouchMove) - img.addEventListener('touchend', handleTouchEnd) - img.addEventListener('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.addEventListener('click', function(e) { + e.stopPropagation(); + container.remove(); + handleInput(); + }); + } }) }, 0) } catch (error) { @@ -1437,21 +1515,34 @@ defineExpose({ // 为图片添加拖拽事件监听器 setTimeout(() => { console.log('Adding drag event listeners to images in delayed setContent') - const imageElements = editorRef.value.querySelectorAll('img.editor-image') - console.log('Found images in delayed setContent:', imageElements.length) - imageElements.forEach(img => { + const imageContainers = editorRef.value.querySelectorAll('.image-container') + console.log('Found image containers in delayed setContent:', imageContainers.length) + imageContainers.forEach(container => { + const img = container.querySelector('img.editor-image') + if (!img) return + console.log('Adding touch listeners to image in delayed setContent:', img) // 先移除可能已有的事件监听器,避免重复 - img.removeEventListener('touchstart', handleTouchStart) - img.removeEventListener('touchmove', handleTouchMove) - img.removeEventListener('touchend', handleTouchEnd) - img.removeEventListener('touchcancel', handleTouchCancel) + container.removeEventListener('touchstart', handleTouchStart) + container.removeEventListener('touchmove', handleTouchMove) + container.removeEventListener('touchend', handleTouchEnd) + container.removeEventListener('touchcancel', handleTouchCancel) // 重新添加事件监听器 - img.addEventListener('touchstart', handleTouchStart) - img.addEventListener('touchmove', handleTouchMove) - img.addEventListener('touchend', handleTouchEnd) - img.addEventListener('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.addEventListener('click', function(e) { + e.stopPropagation(); + container.remove(); + handleInput(); + }); + } }) }, 0) } catch (error) { @@ -1671,11 +1762,16 @@ defineExpose({ text-align: center; } +:deep(.editor-content .image-container) { + display: inline-block; + position: relative; + margin: calc((var(--editor-line-height, 1.6) * 10) * 1px) auto; +} + :deep(.editor-content .editor-image) { max-width: 100%; height: auto; display: block; - margin: calc((var(--editor-line-height, 1.6) * 10) * 1px) auto; object-fit: cover; box-sizing: border-box; border: 0.625rem solid white; @@ -1692,6 +1788,18 @@ defineExpose({ -webkit-tap-highlight-color: transparent; } +:deep(.editor-content .image-delete-btn) { + position: absolute; + top: 8px; + right: 8px; + width: 24px; + height: 24px; + cursor: pointer; + z-index: 10; + display: none; + transition: opacity 0.2s ease; +} + :deep(.editor-content .editor-image.draggable) { cursor: move; }