You've already forked SmartisanNote.Remake
开始完善便签新建、编辑逻辑
This commit is contained in:
@@ -28,6 +28,26 @@ const editorRef = ref(null)
|
||||
const content = ref(props.modelValue || '')
|
||||
const isToolbarVisible = ref(false)
|
||||
|
||||
// 初始化编辑器内容
|
||||
onMounted(() => {
|
||||
console.log('RichTextEditor mounted, initial content:', props.modelValue)
|
||||
if (editorRef.value) {
|
||||
if (props.modelValue) {
|
||||
try {
|
||||
editorRef.value.innerHTML = props.modelValue
|
||||
content.value = props.modelValue
|
||||
console.log('Initial content set successfully')
|
||||
} catch (error) {
|
||||
console.error('Failed to set initial content:', error)
|
||||
}
|
||||
} else {
|
||||
// 即使没有初始内容,也要确保编辑器是可编辑的
|
||||
editorRef.value.contentEditable = true
|
||||
console.log('Editor initialized without initial content')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 工具配置
|
||||
const tools = ref([
|
||||
{
|
||||
@@ -68,6 +88,15 @@ const tools = ref([
|
||||
},
|
||||
])
|
||||
|
||||
// 处理输入事件
|
||||
const handleInput = () => {
|
||||
if (editorRef.value) {
|
||||
content.value = editorRef.value.innerHTML
|
||||
console.log('Input event handled, content:', content.value)
|
||||
emit('update:modelValue', content.value)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查当前选区是否已经在某种格式中
|
||||
const isAlreadyInFormat = formatType => {
|
||||
const selection = window.getSelection()
|
||||
@@ -550,14 +579,6 @@ const insertImage = () => {
|
||||
fileInput.click()
|
||||
}
|
||||
|
||||
// 处理输入事件
|
||||
const handleInput = () => {
|
||||
if (editorRef.value) {
|
||||
content.value = editorRef.value.innerHTML
|
||||
emit('update:modelValue', content.value)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理键盘事件
|
||||
const handleKeydown = e => {
|
||||
// 处理Shift+Enter键换行
|
||||
@@ -710,15 +731,42 @@ const handleToolbarFocusOut = () => {
|
||||
}, 200) // 增加延迟时间,确保有足够时间处理点击事件
|
||||
}
|
||||
|
||||
// 监听外部值变化
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
getContent: () => content.value,
|
||||
setContent: newContent => {
|
||||
content.value = newContent
|
||||
console.log('Setting content in editor:', newContent)
|
||||
content.value = newContent || ''
|
||||
if (editorRef.value) {
|
||||
editorRef.value.innerHTML = newContent
|
||||
try {
|
||||
editorRef.value.innerHTML = content.value
|
||||
console.log('Content set successfully in editorRef')
|
||||
} catch (error) {
|
||||
console.error('Failed to set innerHTML:', error)
|
||||
// 备选方案:使用textContent
|
||||
try {
|
||||
editorRef.value.textContent = content.value
|
||||
console.log('Content set using textContent')
|
||||
} catch (textContentError) {
|
||||
console.error('Failed to set textContent:', textContentError)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果editorRef还不可用,延迟设置
|
||||
console.log('Editor ref is not available, will retry when mounted')
|
||||
setTimeout(() => {
|
||||
if (editorRef.value) {
|
||||
try {
|
||||
editorRef.value.innerHTML = content.value
|
||||
console.log('Content set successfully after delay')
|
||||
} catch (error) {
|
||||
console.error('Failed to set innerHTML after delay:', error)
|
||||
}
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
insertImage,
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -914,31 +962,7 @@ defineExpose({
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 引用格式样式 */
|
||||
:deep(.quote-container) {
|
||||
position: relative;
|
||||
margin: 0 0 12px 0;
|
||||
line-height: var(--editor-line-height, 1.6);
|
||||
}
|
||||
|
||||
:deep(.quote-icon) {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: var(--editor-font-size, 16px);
|
||||
height: var(--editor-font-size, 16px);
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
:deep(.quote-content) {
|
||||
border-left: 3px solid var(--primary);
|
||||
padding: 0 var(--editor-font-size, 16px) 0 32px;
|
||||
margin-left: var(--editor-font-size, 16px);
|
||||
color: var(--text-secondary);
|
||||
background-color: var(--background-secondary);
|
||||
font-style: italic;
|
||||
line-height: var(--editor-line-height, 1.6);
|
||||
}
|
||||
|
||||
.editor-content img {
|
||||
max-width: 100%;
|
||||
@@ -972,71 +996,3 @@ defineExpose({
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// 插入图片
|
||||
const insertImage = () => {
|
||||
// 创建文件输入元素
|
||||
const fileInput = document.createElement('input')
|
||||
fileInput.type = 'file'
|
||||
fileInput.accept = 'image/*'
|
||||
fileInput.style.display = 'none'
|
||||
|
||||
// 添加到文档中
|
||||
document.body.appendChild(fileInput)
|
||||
|
||||
// 监听文件选择事件
|
||||
fileInput.addEventListener('change', function (event) {
|
||||
const file = event.target.files[0]
|
||||
if (file && file.type.startsWith('image/')) {
|
||||
// 创建FileReader读取文件
|
||||
const reader = new FileReader()
|
||||
reader.onload = function (e) {
|
||||
// 获取图片数据URL
|
||||
const imageDataUrl = e.target.result
|
||||
|
||||
// 获取当前选区
|
||||
const selection = window.getSelection()
|
||||
if (selection.rangeCount > 0) {
|
||||
const range = selection.getRangeAt(0)
|
||||
|
||||
// 创建图片元素
|
||||
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'
|
||||
|
||||
// 插入图片到当前光标位置
|
||||
range.insertNode(img)
|
||||
|
||||
// 添加换行
|
||||
const br = document.createElement('br')
|
||||
img.parentNode.insertBefore(br, img.nextSibling)
|
||||
|
||||
// 触发输入事件更新内容
|
||||
handleInput()
|
||||
|
||||
// 重新聚焦到编辑器
|
||||
if (editorRef.value) {
|
||||
editorRef.value.focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
reader.readAsDataURL(file)
|
||||
}
|
||||
|
||||
// 清理文件输入元素
|
||||
document.body.removeChild(fileInput)
|
||||
})
|
||||
|
||||
// 触发文件选择对话框
|
||||
fileInput.click()
|
||||
}
|
||||
|
||||
export default {
|
||||
insertImage
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user