You've already forked SmartisanNote.Remake
新增 编辑器现在可以拖拽图片排序了
This commit is contained in:
@@ -115,16 +115,22 @@ const SLIDE_THRESHOLD = 64 // 4rem 转换为 px
|
|||||||
const handleContainerTouchStart = e => {
|
const handleContainerTouchStart = e => {
|
||||||
// 阻止事件冒泡到父组件
|
// 阻止事件冒泡到父组件
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
// 阻止父级滚动容器的滚动行为
|
||||||
|
e.stopImmediatePropagation()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleContainerTouchMove = e => {
|
const handleContainerTouchMove = e => {
|
||||||
// 阻止事件冒泡到父组件
|
// 阻止事件冒泡到父组件
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
// 阻止父级滚动容器的滚动行为
|
||||||
|
e.stopImmediatePropagation()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleContainerTouchEnd = e => {
|
const handleContainerTouchEnd = e => {
|
||||||
// 阻止事件冒泡到父组件
|
// 阻止事件冒泡到父组件
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
// 阻止父级滚动容器的滚动行为
|
||||||
|
e.stopImmediatePropagation()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理便签点击事件
|
// 处理便签点击事件
|
||||||
@@ -168,6 +174,8 @@ const handleDelete = () => {
|
|||||||
const handleTouchStart = e => {
|
const handleTouchStart = e => {
|
||||||
// 阻止事件冒泡到父组件,防止页面滚动时触发便签滑动
|
// 阻止事件冒泡到父组件,防止页面滚动时触发便签滑动
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
// 阻止父级滚动容器的滚动行为
|
||||||
|
e.stopImmediatePropagation()
|
||||||
// 重置滑动状态
|
// 重置滑动状态
|
||||||
startX.value = e.touches[0].clientX
|
startX.value = e.touches[0].clientX
|
||||||
startY.value = e.touches[0].clientY // 记录起始Y坐标
|
startY.value = e.touches[0].clientY // 记录起始Y坐标
|
||||||
@@ -187,12 +195,18 @@ const handleTouchMove = e => {
|
|||||||
const diffY = currentY - startY.value
|
const diffY = currentY - startY.value
|
||||||
|
|
||||||
// 如果已经确定是滚动,则不再处理
|
// 如果已经确定是滚动,则不再处理
|
||||||
if (isScrolling.value) return
|
if (isScrolling.value) {
|
||||||
|
// 阻止事件冒泡到父组件,防止页面滚动时触发便签滑动
|
||||||
|
e.stopPropagation()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 判断是滚动还是滑动操作
|
// 判断是滚动还是滑动操作
|
||||||
// 如果Y轴移动距离大于X轴移动距离,则认为是滚动
|
// 如果Y轴移动距离大于X轴移动距离,则认为是滚动
|
||||||
if (Math.abs(diffY) > Math.abs(diffX)) {
|
if (Math.abs(diffY) > Math.abs(diffX)) {
|
||||||
isScrolling.value = true
|
isScrolling.value = true
|
||||||
|
// 阻止事件冒泡到父组件,防止页面滚动时触发便签滑动
|
||||||
|
e.stopPropagation()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,6 +256,8 @@ const handleTouchEnd = e => {
|
|||||||
|
|
||||||
// 阻止事件冒泡到父组件,防止页面滚动时触发便签滑动
|
// 阻止事件冒泡到父组件,防止页面滚动时触发便签滑动
|
||||||
e?.stopPropagation()
|
e?.stopPropagation()
|
||||||
|
// 阻止父级滚动容器的滚动行为
|
||||||
|
e?.stopImmediatePropagation()
|
||||||
|
|
||||||
// 如果滑动超过阈值,保持滑出状态;否则回弹
|
// 如果滑动超过阈值,保持滑出状态;否则回弹
|
||||||
if (slideOffset.value >= SLIDE_THRESHOLD) {
|
if (slideOffset.value >= SLIDE_THRESHOLD) {
|
||||||
|
|||||||
@@ -577,6 +577,66 @@ const insertTodoList = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理图片拖拽开始
|
||||||
|
const handleImageDragStart = (e) => {
|
||||||
|
e.dataTransfer.effectAllowed = 'move'
|
||||||
|
e.target.classList.add('dragging')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理图片拖拽经过
|
||||||
|
const handleImageDragOver = (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.dataTransfer.dropEffect = 'move'
|
||||||
|
|
||||||
|
const target = e.target
|
||||||
|
const draggingElement = document.querySelector('img.editor-image.dragging')
|
||||||
|
|
||||||
|
if (draggingElement && target !== draggingElement && target.classList.contains('editor-image')) {
|
||||||
|
const rect = target.getBoundingClientRect()
|
||||||
|
const midpoint = rect.top + rect.height / 2
|
||||||
|
|
||||||
|
if (e.clientY < midpoint) {
|
||||||
|
// 在目标元素上方插入
|
||||||
|
target.parentNode.insertBefore(draggingElement, target)
|
||||||
|
// 同时移动拖拽手柄
|
||||||
|
const targetHandle = target.nextElementSibling
|
||||||
|
const draggingHandle = draggingElement.nextElementSibling
|
||||||
|
if (targetHandle && targetHandle.classList.contains('image-drag-handle') &&
|
||||||
|
draggingHandle && draggingHandle.classList.contains('image-drag-handle')) {
|
||||||
|
target.parentNode.insertBefore(draggingHandle, targetHandle)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 在目标元素下方插入
|
||||||
|
target.parentNode.insertBefore(draggingElement, target.nextSibling)
|
||||||
|
// 同时移动拖拽手柄
|
||||||
|
const targetHandle = target.nextElementSibling
|
||||||
|
const draggingHandle = draggingElement.nextElementSibling
|
||||||
|
if (targetHandle && targetHandle.classList.contains('image-drag-handle') &&
|
||||||
|
draggingHandle && draggingHandle.classList.contains('image-drag-handle')) {
|
||||||
|
target.parentNode.insertBefore(draggingHandle, targetHandle.nextSibling)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理图片拖拽释放
|
||||||
|
const handleImageDrop = (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
const draggingElement = document.querySelector('img.editor-image.dragging')
|
||||||
|
if (draggingElement) {
|
||||||
|
draggingElement.classList.remove('dragging')
|
||||||
|
handleInput() // 触发内容更新
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理图片拖拽结束
|
||||||
|
const handleImageDragEnd = (e) => {
|
||||||
|
const draggingElement = document.querySelector('img.editor-image.dragging')
|
||||||
|
if (draggingElement) {
|
||||||
|
draggingElement.classList.remove('dragging')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 插入图片
|
// 插入图片
|
||||||
const insertImage = () => {
|
const insertImage = () => {
|
||||||
// 创建文件输入元素
|
// 创建文件输入元素
|
||||||
@@ -607,6 +667,17 @@ const insertImage = () => {
|
|||||||
const img = document.createElement('img')
|
const img = document.createElement('img')
|
||||||
img.src = imageDataUrl
|
img.src = imageDataUrl
|
||||||
img.className = 'editor-image'
|
img.className = 'editor-image'
|
||||||
|
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' // 移除默认焦点轮廓
|
||||||
|
|
||||||
// 创建一个临时图片来获取原始尺寸
|
// 创建一个临时图片来获取原始尺寸
|
||||||
const tempImg = new Image()
|
const tempImg = new Image()
|
||||||
@@ -641,12 +712,110 @@ const insertImage = () => {
|
|||||||
|
|
||||||
// 确保图片与基准线对齐
|
// 确保图片与基准线对齐
|
||||||
img.style.verticalAlign = 'top'
|
img.style.verticalAlign = 'top'
|
||||||
|
|
||||||
|
// 创建拖拽手柄
|
||||||
|
const dragHandle = document.createElement('div')
|
||||||
|
dragHandle.className = 'image-drag-handle'
|
||||||
|
dragHandle.style.position = 'absolute'
|
||||||
|
dragHandle.style.top = '0.3125rem'
|
||||||
|
dragHandle.style.right = '0.3125rem'
|
||||||
|
dragHandle.style.width = '1.5rem'
|
||||||
|
dragHandle.style.height = '1.5rem'
|
||||||
|
dragHandle.style.backgroundImage = "url('/assets/icons/drawable-xxhdpi/detail_note_item_image_move.png')"
|
||||||
|
dragHandle.style.backgroundSize = 'contain'
|
||||||
|
dragHandle.style.backgroundRepeat = 'no-repeat'
|
||||||
|
dragHandle.style.cursor = 'move'
|
||||||
|
dragHandle.style.display = 'none'
|
||||||
|
dragHandle.style.zIndex = '1000'
|
||||||
|
dragHandle.style.pointerEvents = 'auto'
|
||||||
|
dragHandle.style.position = 'absolute'
|
||||||
|
|
||||||
|
// 调试信息
|
||||||
|
console.log('Creating drag handle for image')
|
||||||
|
|
||||||
|
// 将拖拽手柄添加到图片后面(使用insertAdjacentElement)
|
||||||
|
img.insertAdjacentElement('afterend', dragHandle)
|
||||||
}
|
}
|
||||||
tempImg.src = imageDataUrl
|
tempImg.src = imageDataUrl
|
||||||
|
|
||||||
|
// 添加事件监听器来显示/隐藏拖拽手柄
|
||||||
|
img.addEventListener('focus', function() {
|
||||||
|
const dragHandle = img.nextElementSibling
|
||||||
|
if (dragHandle && dragHandle.classList.contains('image-drag-handle')) {
|
||||||
|
dragHandle.classList.add('visible')
|
||||||
|
dragHandle.style.display = 'block' // 直接设置显示样式
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
img.addEventListener('blur', function() {
|
||||||
|
const dragHandle = img.nextElementSibling
|
||||||
|
if (dragHandle && dragHandle.classList.contains('image-drag-handle')) {
|
||||||
|
// 延迟隐藏,确保用户有时间将鼠标移到手柄上
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!dragHandle.matches(':hover')) {
|
||||||
|
dragHandle.classList.remove('visible')
|
||||||
|
dragHandle.style.display = 'none' // 直接设置隐藏样式
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
img.addEventListener('mouseover', function() {
|
||||||
|
const dragHandle = img.nextElementSibling
|
||||||
|
if (dragHandle && dragHandle.classList.contains('image-drag-handle')) {
|
||||||
|
dragHandle.classList.add('visible')
|
||||||
|
dragHandle.style.display = 'block' // 直接设置显示样式
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
img.addEventListener('mouseout', function(e) {
|
||||||
|
const dragHandle = img.nextElementSibling
|
||||||
|
if (dragHandle && dragHandle.classList.contains('image-drag-handle')) {
|
||||||
|
// 延迟隐藏,确保用户有时间将鼠标移到手柄上
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!dragHandle.matches(':hover') && document.activeElement !== img) {
|
||||||
|
dragHandle.classList.remove('visible')
|
||||||
|
dragHandle.style.display = 'none' // 直接设置隐藏样式
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 添加拖拽手柄的事件监听器
|
||||||
|
setTimeout(() => {
|
||||||
|
const dragHandle = img.nextElementSibling
|
||||||
|
if (dragHandle && dragHandle.classList.contains('image-drag-handle')) {
|
||||||
|
dragHandle.addEventListener('mouseover', function() {
|
||||||
|
dragHandle.classList.add('visible')
|
||||||
|
dragHandle.style.display = 'block' // 直接设置显示样式
|
||||||
|
})
|
||||||
|
|
||||||
|
dragHandle.addEventListener('mouseout', function(e) {
|
||||||
|
// 延迟隐藏,确保用户有时间将鼠标移到图片上
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!img.matches(':hover') && document.activeElement !== img) {
|
||||||
|
dragHandle.classList.remove('visible')
|
||||||
|
dragHandle.style.display = 'none' // 直接设置隐藏样式
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
// 添加拖拽功能
|
||||||
|
img.draggable = true
|
||||||
|
img.addEventListener('dragstart', handleImageDragStart)
|
||||||
|
img.addEventListener('dragover', handleImageDragOver)
|
||||||
|
img.addEventListener('drop', handleImageDrop)
|
||||||
|
img.addEventListener('dragend', handleImageDragEnd)
|
||||||
|
|
||||||
// 插入图片到当前光标位置
|
// 插入图片到当前光标位置
|
||||||
range.insertNode(img)
|
range.insertNode(img)
|
||||||
|
|
||||||
|
// 调试信息
|
||||||
|
console.log('Image inserted:', img)
|
||||||
|
console.log('Next sibling (should be drag handle):', img.nextSibling)
|
||||||
|
|
||||||
// 添加换行
|
// 添加换行
|
||||||
const br = document.createElement('br')
|
const br = document.createElement('br')
|
||||||
img.parentNode.insertBefore(br, img.nextSibling)
|
img.parentNode.insertBefore(br, img.nextSibling)
|
||||||
@@ -941,6 +1110,99 @@ const adjustExistingImages = () => {
|
|||||||
tempImg.src = img.src
|
tempImg.src = img.src
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 为现有图片添加拖拽功能
|
||||||
|
images.forEach(img => {
|
||||||
|
// 确保图片有拖拽属性
|
||||||
|
if (!img.hasAttribute('draggable')) {
|
||||||
|
img.draggable = true
|
||||||
|
|
||||||
|
// 添加拖拽事件监听器
|
||||||
|
img.addEventListener('dragstart', handleImageDragStart)
|
||||||
|
img.addEventListener('dragover', handleImageDragOver)
|
||||||
|
img.addEventListener('drop', handleImageDrop)
|
||||||
|
img.addEventListener('dragend', handleImageDragEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否已存在拖拽手柄
|
||||||
|
let existingHandle = img.nextElementSibling
|
||||||
|
if (!existingHandle || !existingHandle.classList.contains('image-drag-handle')) {
|
||||||
|
// 创建拖拽手柄
|
||||||
|
const dragHandle = document.createElement('div')
|
||||||
|
dragHandle.className = 'image-drag-handle'
|
||||||
|
dragHandle.style.position = 'absolute'
|
||||||
|
dragHandle.style.top = '0.3125rem'
|
||||||
|
dragHandle.style.right = '0.3125rem'
|
||||||
|
dragHandle.style.width = '1.5rem'
|
||||||
|
dragHandle.style.height = '1.5rem'
|
||||||
|
dragHandle.style.backgroundImage = "url('/assets/icons/drawable-xxhdpi/detail_note_item_image_move.png')"
|
||||||
|
dragHandle.style.backgroundSize = 'contain'
|
||||||
|
dragHandle.style.backgroundRepeat = 'no-repeat'
|
||||||
|
dragHandle.style.cursor = 'move'
|
||||||
|
dragHandle.style.display = 'none'
|
||||||
|
dragHandle.style.zIndex = '1000'
|
||||||
|
dragHandle.style.pointerEvents = 'auto'
|
||||||
|
dragHandle.style.position = 'absolute'
|
||||||
|
|
||||||
|
// 调试信息
|
||||||
|
console.log('Creating drag handle for existing image')
|
||||||
|
|
||||||
|
// 将拖拽手柄添加到图片后面
|
||||||
|
img.insertAdjacentElement('afterend', dragHandle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保拖拽手柄存在后再添加事件监听器
|
||||||
|
setTimeout(() => {
|
||||||
|
const dragHandle = img.nextElementSibling
|
||||||
|
if (dragHandle && dragHandle.classList.contains('image-drag-handle')) {
|
||||||
|
// 添加事件监听器来显示/隐藏拖拽手柄
|
||||||
|
img.addEventListener('focus', function() {
|
||||||
|
dragHandle.classList.add('visible')
|
||||||
|
dragHandle.style.display = 'block' // 直接设置显示样式
|
||||||
|
})
|
||||||
|
|
||||||
|
img.addEventListener('blur', function() {
|
||||||
|
// 延迟隐藏,确保用户有时间将鼠标移到手柄上
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!dragHandle.matches(':hover')) {
|
||||||
|
dragHandle.classList.remove('visible')
|
||||||
|
dragHandle.style.display = 'none' // 直接设置隐藏样式
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
})
|
||||||
|
|
||||||
|
img.addEventListener('mouseover', function() {
|
||||||
|
dragHandle.classList.add('visible')
|
||||||
|
dragHandle.style.display = 'block' // 直接设置显示样式
|
||||||
|
})
|
||||||
|
|
||||||
|
img.addEventListener('mouseout', function(e) {
|
||||||
|
// 延迟隐藏,确保用户有时间将鼠标移到手柄上
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!dragHandle.matches(':hover') && document.activeElement !== img) {
|
||||||
|
dragHandle.classList.remove('visible')
|
||||||
|
dragHandle.style.display = 'none' // 直接设置隐藏样式
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
})
|
||||||
|
|
||||||
|
dragHandle.addEventListener('mouseover', function() {
|
||||||
|
dragHandle.classList.add('visible')
|
||||||
|
dragHandle.style.display = 'block' // 直接设置显示样式
|
||||||
|
})
|
||||||
|
|
||||||
|
dragHandle.addEventListener('mouseout', function(e) {
|
||||||
|
// 延迟隐藏,确保用户有时间将鼠标移到图片上
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!img.matches(':hover') && document.activeElement !== img) {
|
||||||
|
dragHandle.classList.remove('visible')
|
||||||
|
dragHandle.style.display = 'none' // 直接设置隐藏样式
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, 0)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}, 0)
|
}, 0)
|
||||||
}
|
}
|
||||||
@@ -955,7 +1217,7 @@ defineExpose({
|
|||||||
try {
|
try {
|
||||||
editorRef.value.innerHTML = content.value
|
editorRef.value.innerHTML = content.value
|
||||||
console.log('Content set successfully in editorRef')
|
console.log('Content set successfully in editorRef')
|
||||||
// 调整已有图片的高度
|
// 调整已有图片的高度并添加拖拽功能
|
||||||
adjustExistingImages()
|
adjustExistingImages()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to set innerHTML:', error)
|
console.error('Failed to set innerHTML:', error)
|
||||||
@@ -975,7 +1237,7 @@ defineExpose({
|
|||||||
try {
|
try {
|
||||||
editorRef.value.innerHTML = content.value
|
editorRef.value.innerHTML = content.value
|
||||||
console.log('Content set successfully after delay')
|
console.log('Content set successfully after delay')
|
||||||
// 调整已有图片的高度
|
// 调整已有图片的高度并添加拖拽功能
|
||||||
adjustExistingImages()
|
adjustExistingImages()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to set innerHTML after delay:', error)
|
console.error('Failed to set innerHTML after delay:', error)
|
||||||
@@ -1205,6 +1467,43 @@ defineExpose({
|
|||||||
border-radius: 0.2rem;
|
border-radius: 0.2rem;
|
||||||
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.18);
|
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.18);
|
||||||
background: var(--background-secondary);
|
background: var(--background-secondary);
|
||||||
|
position: relative;
|
||||||
|
outline: none; /* 移除默认焦点轮廓 */
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.editor-content .editor-image.draggable) {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.editor-content .image-drag-handle) {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.3125rem;
|
||||||
|
right: 0.3125rem;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
background-image: url('/assets/icons/drawable-xxhdpi/detail_note_item_image_move.png');
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
cursor: move;
|
||||||
|
display: none;
|
||||||
|
z-index: 1000;
|
||||||
|
pointer-events: auto; /* 确保手柄可以接收鼠标事件 */
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.editor-content .editor-image:focus + .image-drag-handle),
|
||||||
|
:deep(.editor-content .editor-image:hover + .image-drag-handle),
|
||||||
|
:deep(.editor-content .image-drag-handle:hover) {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 强制显示拖拽手柄的类 */
|
||||||
|
:deep(.editor-content .image-drag-handle.visible) {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.editor-content .editor-image.dragging) {
|
||||||
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 待办事项样式 */
|
/* 待办事项样式 */
|
||||||
|
|||||||
Reference in New Issue
Block a user