diff --git a/src/components/NoteItem.vue b/src/components/NoteItem.vue index f9f2730..52589a4 100644 --- a/src/components/NoteItem.vue +++ b/src/components/NoteItem.vue @@ -14,7 +14,7 @@
- {{ content }} + {{ displayContent }}
@@ -81,6 +81,23 @@ const formattedDate = computed(() => { return props.date }) +// 处理显示内容,过滤HTML标签并只显示第一行 +const displayContent = computed(() => { + console.log('NoteItem content:', props.content) + // 过滤HTML标签 + let text = props.content.replace(/<[^>]*>/g, '') + console.log('NoteItem text without HTML:', text) + + // 处理换行符,统一为\n + text = text.replace(/\\n/g, '\n') + + // 按换行符分割并获取第一行 + const lines = text.split('\n') + + // 返回第一行内容,如果为空则显示默认文本 + return lines[0]?.trim() || '无内容' +}) + // 滑动阈值(删除按钮宽度) const SLIDE_THRESHOLD = 64 // 4rem 转换为 px diff --git a/src/components/RichTextEditor.vue b/src/components/RichTextEditor.vue index 27940c4..45b335d 100644 --- a/src/components/RichTextEditor.vue +++ b/src/components/RichTextEditor.vue @@ -37,6 +37,8 @@ onMounted(() => { editorRef.value.innerHTML = props.modelValue content.value = props.modelValue console.log('Initial content set successfully') + // 调整已有图片的高度 + adjustExistingImages() } catch (error) { console.error('Failed to set initial content:', error) } @@ -91,8 +93,20 @@ const tools = ref([ // 处理输入事件 const handleInput = () => { if (editorRef.value) { - content.value = editorRef.value.innerHTML - console.log('Input event handled, content:', content.value) + // 获取编辑器内容 + let innerHTML = editorRef.value.innerHTML + + // 处理换行符,确保在段落之间有明确的分隔 + innerHTML = innerHTML.replace(/<\/p>

/g, '

\n

') + // 处理div标签换行 + innerHTML = innerHTML.replace(/<\/div>

/g, '
\n
') + // 处理br标签换行 + innerHTML = innerHTML.replace(/
/g, '\n') + innerHTML = innerHTML.replace(//g, '\n') + // 处理div标签内的换行 + innerHTML = innerHTML.replace(/
/g, '\n
') + + content.value = innerHTML emit('update:modelValue', content.value) } } @@ -547,10 +561,42 @@ const insertImage = () => { const img = document.createElement('img') img.src = imageDataUrl img.className = 'editor-image' - img.style.maxWidth = '100%' - img.style.height = 'auto' - img.style.display = 'block' - img.style.margin = '0 auto' + + // 创建一个临时图片来获取原始尺寸 + const tempImg = new Image() + tempImg.onload = function () { + // 获取CSS变量 + const editorFontSize = getComputedStyle(document.documentElement).getPropertyValue('--editor-font-size').trim() || '16px' + const editorLineHeight = getComputedStyle(document.documentElement).getPropertyValue('--editor-line-height').trim() || '1.6' + const fontSize = parseInt(editorFontSize) + const lineHeight = parseFloat(editorLineHeight) + + // 计算行高 + const computedLineHeight = fontSize * lineHeight + + // 获取编辑器的宽度(减去一些内边距) + const editorWidth = editorRef.value.offsetWidth - 20 // 20px为左右内边距 + + // 按宽度撑满计算调整后的尺寸 + const originalHeight = tempImg.height + const originalWidth = tempImg.width + const scaleRatio = editorWidth / originalWidth + const scaledHeight = originalHeight * scaleRatio + + // 计算调整后的高度,使其为行高的整数倍 + const scaleFactor = Math.max(1, Math.round(scaledHeight / computedLineHeight)) + const adjustedHeight = scaleFactor * computedLineHeight + + // 按比例调整宽度 + const adjustedWidth = (originalWidth * adjustedHeight) / originalHeight + + img.style.height = `${adjustedHeight}px` + img.style.width = `${adjustedWidth}px` + + // 确保图片与基准线对齐 + img.style.verticalAlign = 'top' + } + tempImg.src = imageDataUrl // 插入图片到当前光标位置 range.insertNode(img) @@ -731,6 +777,59 @@ const handleToolbarFocusOut = () => { }, 200) // 增加延迟时间,确保有足够时间处理点击事件 } +// 调整已有图片的高度 +const adjustExistingImages = () => { + // 等待DOM更新完成 + setTimeout(() => { + if (editorRef.value) { + const images = editorRef.value.querySelectorAll('img.editor-image') + images.forEach(img => { + // 只处理还没有调整过高度的图片 + if (!img.dataset.heightAdjusted) { + // 创建一个临时图片来获取原始尺寸 + const tempImg = new Image() + tempImg.onload = function () { + // 获取CSS变量 + const editorFontSize = getComputedStyle(document.documentElement).getPropertyValue('--editor-font-size').trim() || '16px' + const editorLineHeight = getComputedStyle(document.documentElement).getPropertyValue('--editor-line-height').trim() || '1.6' + const fontSize = parseInt(editorFontSize) + const lineHeight = parseFloat(editorLineHeight) + + // 计算行高 + const computedLineHeight = fontSize * lineHeight + + // 获取编辑器的宽度(减去一些内边距) + const editorWidth = editorRef.value.offsetWidth - 20 // 20px为左右内边距 + + // 按宽度撑满计算调整后的尺寸 + const originalHeight = tempImg.height + const originalWidth = tempImg.width + const scaleRatio = editorWidth / originalWidth + const scaledHeight = originalHeight * scaleRatio + + // 计算调整后的高度,使其为行高的整数倍 + const scaleFactor = Math.max(1, Math.round(scaledHeight / computedLineHeight)) + const adjustedHeight = scaleFactor * computedLineHeight + + // 按比例调整宽度 + const adjustedWidth = (originalWidth * adjustedHeight) / originalHeight + + img.style.height = `${adjustedHeight}px` + img.style.width = `${adjustedWidth}px` + + // 确保图片与基准线对齐 + img.style.verticalAlign = 'top' + + // 标记图片已调整过高度 + img.dataset.heightAdjusted = 'true' + } + tempImg.src = img.src + } + }) + } + }, 0) +} + // 暴露方法给父组件 defineExpose({ getContent: () => content.value, @@ -741,6 +840,8 @@ defineExpose({ try { editorRef.value.innerHTML = content.value console.log('Content set successfully in editorRef') + // 调整已有图片的高度 + adjustExistingImages() } catch (error) { console.error('Failed to set innerHTML:', error) // 备选方案:使用textContent @@ -759,6 +860,8 @@ defineExpose({ try { editorRef.value.innerHTML = content.value console.log('Content set successfully after delay') + // 调整已有图片的高度 + adjustExistingImages() } catch (error) { console.error('Failed to set innerHTML after delay:', error) } @@ -774,7 +877,7 @@ defineExpose({ .editor-container { display: flex; flex-direction: column; - height: 100%; + min-height: 100%; background-color: var(--background-card); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } @@ -962,30 +1065,37 @@ defineExpose({ text-align: center; } - - -.editor-content img { +:deep(.editor-content .editor-image) { max-width: 100%; height: auto; display: block; - margin: 0 auto; + margin: calc((var(--editor-line-height, 1.6) * 10) * 1px) auto; + object-fit: cover; + box-sizing: border-box; + border: 10px solid white; + border-radius: 0.2rem; + box-shadow: 0 1px 5px rgba(0, 0, 0, 0.18); } /* 待办事项样式 */ :deep(.todo-container) { display: flex; - align-items: center; + align-items: flex-start; margin: 0; line-height: var(--editor-line-height, 1.6); + position: relative; + padding-left: calc(var(--editor-font-size, 16px) * 1.5); } :deep(.todo-icon) { - width: calc(var(--editor-font-size, 16px) * 2); - height: calc(var(--editor-font-size, 16px) * 2); - margin-right: 3px; - margin-top: 0; + width: calc(var(--editor-font-size, 16px) * 1.5); + height: calc(var(--editor-font-size, 16px) * 1.5); cursor: pointer; flex-shrink: 0; + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); } :deep(.todo-content) { diff --git a/src/pages/NoteEditorPage.vue b/src/pages/NoteEditorPage.vue index caffce9..5c3c218 100644 --- a/src/pages/NoteEditorPage.vue +++ b/src/pages/NoteEditorPage.vue @@ -277,14 +277,14 @@ const setShowAlert = value => { } .rich-text-editor { - height: 100%; + min-height: 100%; } .header-info { display: flex; justify-content: flex-start; gap: 10px; - padding: 1.5rem 16px 0.7rem 16px; + padding: 1rem 16px 0.7rem 16px; background-color: var(--background-card); border-bottom: 1px solid var(--border); font-size: 0.7rem;