123
This commit is contained in:
parent
27c69a9b6d
commit
66b28bbe72
|
|
@ -26,7 +26,7 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="内容" prop="content">
|
<el-form-item label="内容" prop="content">
|
||||||
<div v-if="dialogVisible" class="editor-container">
|
<div v-if="editorReady" class="editor-container">
|
||||||
<Toolbar
|
<Toolbar
|
||||||
:editor="editorRef"
|
:editor="editorRef"
|
||||||
:defaultConfig="toolbarConfig"
|
:defaultConfig="toolbarConfig"
|
||||||
|
|
@ -34,13 +34,16 @@
|
||||||
class="editor-toolbar"
|
class="editor-toolbar"
|
||||||
/>
|
/>
|
||||||
<Editor
|
<Editor
|
||||||
v-model="formData.content"
|
|
||||||
:defaultConfig="editorConfig"
|
:defaultConfig="editorConfig"
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
class="editor-content"
|
class="editor-content"
|
||||||
@onCreated="handleCreated"
|
@onCreated="handleCreated"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="dialogVisible" class="editor-loading">
|
||||||
|
<el-icon class="is-loading"><Loading /></el-icon>
|
||||||
|
<span>加载编辑器中...</span>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
|
|
@ -54,8 +57,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, computed, watch, shallowRef, onBeforeUnmount } from 'vue'
|
import { ref, reactive, computed, watch, shallowRef, onBeforeUnmount, nextTick } from 'vue'
|
||||||
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
|
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
|
||||||
|
import { Loading } from '@element-plus/icons-vue'
|
||||||
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
||||||
import type { IDomEditor, IEditorConfig, IToolbarConfig } from '@wangeditor/editor'
|
import type { IDomEditor, IEditorConfig, IToolbarConfig } from '@wangeditor/editor'
|
||||||
import '@wangeditor/editor/dist/css/style.css'
|
import '@wangeditor/editor/dist/css/style.css'
|
||||||
|
|
@ -84,6 +88,7 @@ const dialogVisible = computed({
|
||||||
|
|
||||||
// 编辑器实例
|
// 编辑器实例
|
||||||
const editorRef = shallowRef<IDomEditor>()
|
const editorRef = shallowRef<IDomEditor>()
|
||||||
|
const editorReady = ref(false)
|
||||||
const mode = 'default'
|
const mode = 'default'
|
||||||
|
|
||||||
// 工具栏配置
|
// 工具栏配置
|
||||||
|
|
@ -159,7 +164,7 @@ const formRules: FormRules = {
|
||||||
|
|
||||||
// 清理 HTML 内容,修复可能导致编辑器解析错误的格式问题
|
// 清理 HTML 内容,修复可能导致编辑器解析错误的格式问题
|
||||||
const cleanHtmlContent = (html: string): string => {
|
const cleanHtmlContent = (html: string): string => {
|
||||||
if (!html) return ''
|
if (!html) return '<p></p>'
|
||||||
|
|
||||||
// 修复以分号开头的 style 属性(如 style=";font-family:宋体")
|
// 修复以分号开头的 style 属性(如 style=";font-family:宋体")
|
||||||
let cleaned = html.replace(/style=";/g, 'style="')
|
let cleaned = html.replace(/style=";/g, 'style="')
|
||||||
|
|
@ -173,109 +178,82 @@ const cleanHtmlContent = (html: string): string => {
|
||||||
// 移除 style 属性开头的分号
|
// 移除 style 属性开头的分号
|
||||||
cleaned = cleaned.replace(/style=";\s*/g, 'style="')
|
cleaned = cleaned.replace(/style=";\s*/g, 'style="')
|
||||||
|
|
||||||
return cleaned
|
// 移除可能导致问题的特殊字符
|
||||||
}
|
cleaned = cleaned.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F]/g, '')
|
||||||
|
|
||||||
// 安全地设置编辑器内容
|
|
||||||
const safeSetEditorContent = (editor: IDomEditor, content: string) => {
|
|
||||||
if (!editor || editor.isDestroyed) return
|
|
||||||
|
|
||||||
try {
|
return cleaned || '<p></p>'
|
||||||
// 清理 HTML 内容
|
|
||||||
const cleanedContent = cleanHtmlContent(content)
|
|
||||||
|
|
||||||
// 先清空编辑器
|
|
||||||
editor.clear()
|
|
||||||
|
|
||||||
// 使用 setTimeout 确保 clear 操作完成
|
|
||||||
setTimeout(() => {
|
|
||||||
if (!editor.isDestroyed) {
|
|
||||||
try {
|
|
||||||
editor.setHtml(cleanedContent)
|
|
||||||
} catch (e) {
|
|
||||||
console.error('[DanyeFormDialog] Error setting HTML content:', e)
|
|
||||||
// 如果设置失败,尝试设置纯文本
|
|
||||||
try {
|
|
||||||
// 提取纯文本内容
|
|
||||||
const tempDiv = document.createElement('div')
|
|
||||||
tempDiv.innerHTML = cleanedContent
|
|
||||||
const textContent = tempDiv.textContent || tempDiv.innerText || ''
|
|
||||||
editor.insertText(textContent)
|
|
||||||
} catch (e2) {
|
|
||||||
console.error('[DanyeFormDialog] Error setting text content:', e2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 50)
|
|
||||||
} catch (e) {
|
|
||||||
console.error('[DanyeFormDialog] Error in safeSetEditorContent:', e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 编辑器创建完成
|
// 编辑器创建完成
|
||||||
const handleCreated = (editor: IDomEditor) => {
|
const handleCreated = (editor: IDomEditor) => {
|
||||||
console.log('[DanyeFormDialog] handleCreated called, editor:', editor)
|
console.log('[DanyeFormDialog] handleCreated called')
|
||||||
console.log('[DanyeFormDialog] editor.isDestroyed:', editor.isDestroyed)
|
|
||||||
editorRef.value = editor
|
editorRef.value = editor
|
||||||
|
|
||||||
// 如果有内容,设置到编辑器
|
// 延迟设置内容,确保编辑器完全初始化
|
||||||
if (formData.content) {
|
nextTick(() => {
|
||||||
console.log('[DanyeFormDialog] Setting initial content to editor:', formData.content.substring(0, 100))
|
setTimeout(() => {
|
||||||
safeSetEditorContent(editor, formData.content)
|
if (editor && !editor.isDestroyed && formData.content) {
|
||||||
}
|
try {
|
||||||
|
const cleanedContent = cleanHtmlContent(formData.content)
|
||||||
|
console.log('[DanyeFormDialog] Setting cleaned content')
|
||||||
|
editor.setHtml(cleanedContent)
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[DanyeFormDialog] Error setting content:', e)
|
||||||
|
// 如果设置失败,尝试设置为空
|
||||||
|
try {
|
||||||
|
editor.setHtml('<p></p>')
|
||||||
|
} catch (e2) {
|
||||||
|
console.error('[DanyeFormDialog] Error setting empty content:', e2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
editorReady.value = true
|
||||||
|
}, 100)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听弹窗打开,初始化数据
|
// 监听弹窗打开,初始化数据
|
||||||
watch(() => props.modelValue, (visible) => {
|
watch(() => props.modelValue, (visible) => {
|
||||||
console.log('[DanyeFormDialog] modelValue changed:', visible, 'danye:', props.danye?.id)
|
console.log('[DanyeFormDialog] modelValue changed:', visible)
|
||||||
if (visible && props.danye) {
|
if (visible && props.danye) {
|
||||||
formData.title = props.danye.title
|
formData.title = props.danye.title
|
||||||
formData.content = props.danye.content || ''
|
formData.content = props.danye.content || ''
|
||||||
console.log('[DanyeFormDialog] formData.content set to:', formData.content.substring(0, 100))
|
editorReady.value = false
|
||||||
console.log('[DanyeFormDialog] editorRef.value:', editorRef.value)
|
|
||||||
console.log('[DanyeFormDialog] editorRef.value?.isDestroyed:', editorRef.value?.isDestroyed)
|
|
||||||
|
|
||||||
// 如果编辑器已存在且未销毁,直接设置内容
|
|
||||||
if (editorRef.value && !editorRef.value.isDestroyed) {
|
|
||||||
safeSetEditorContent(editorRef.value, formData.content)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 监听 dialogVisible 变化
|
// 监听 dialogVisible 变化
|
||||||
watch(dialogVisible, (visible) => {
|
watch(dialogVisible, (visible) => {
|
||||||
console.log('[DanyeFormDialog] dialogVisible changed:', visible)
|
console.log('[DanyeFormDialog] dialogVisible changed:', visible)
|
||||||
|
if (!visible) {
|
||||||
|
editorReady.value = false
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 组件销毁时销毁编辑器
|
// 组件销毁时销毁编辑器
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
console.log('[DanyeFormDialog] onBeforeUnmount called')
|
|
||||||
const editor = editorRef.value
|
const editor = editorRef.value
|
||||||
if (editor) {
|
if (editor && !editor.isDestroyed) {
|
||||||
console.log('[DanyeFormDialog] Destroying editor in onBeforeUnmount')
|
|
||||||
editor.destroy()
|
editor.destroy()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 重置表单
|
// 重置表单
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
console.log('[DanyeFormDialog] resetForm called')
|
|
||||||
formData.title = ''
|
formData.title = ''
|
||||||
formData.content = ''
|
formData.content = ''
|
||||||
|
editorReady.value = false
|
||||||
formRef.value?.resetFields()
|
formRef.value?.resetFields()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭弹窗
|
// 关闭弹窗
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
console.log('[DanyeFormDialog] handleClose called')
|
|
||||||
console.log('[DanyeFormDialog] editorRef.value before destroy:', editorRef.value)
|
|
||||||
// 先销毁编辑器实例
|
// 先销毁编辑器实例
|
||||||
if (editorRef.value) {
|
if (editorRef.value && !editorRef.value.isDestroyed) {
|
||||||
console.log('[DanyeFormDialog] Destroying editor, isDestroyed:', editorRef.value.isDestroyed)
|
|
||||||
editorRef.value.destroy()
|
editorRef.value.destroy()
|
||||||
editorRef.value = undefined
|
editorRef.value = undefined
|
||||||
console.log('[DanyeFormDialog] Editor destroyed and set to undefined')
|
|
||||||
}
|
}
|
||||||
|
editorReady.value = false
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
resetForm()
|
resetForm()
|
||||||
}
|
}
|
||||||
|
|
@ -290,6 +268,11 @@ const handleSubmit = async () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 从编辑器获取最新内容
|
||||||
|
if (editorRef.value && !editorRef.value.isDestroyed) {
|
||||||
|
formData.content = editorRef.value.getHtml()
|
||||||
|
}
|
||||||
|
|
||||||
submitLoading.value = true
|
submitLoading.value = true
|
||||||
try {
|
try {
|
||||||
const submitData: DanyeUpdateRequest = {
|
const submitData: DanyeUpdateRequest = {
|
||||||
|
|
@ -312,6 +295,10 @@ const handleSubmit = async () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.page-container {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.editor-container {
|
.editor-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 1px solid #dcdfe6;
|
border: 1px solid #dcdfe6;
|
||||||
|
|
@ -329,6 +316,17 @@ const handleSubmit = async () => {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.editor-loading {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 400px;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #909399;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.form-tip {
|
.form-tip {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #909399;
|
color: #909399;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user