This commit is contained in:
zpc 2026-02-08 01:41:01 +08:00
parent 27c69a9b6d
commit 66b28bbe72

View File

@ -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, '')
// return cleaned || '<p></p>'
const safeSetEditorContent = (editor: IDomEditor, content: string) => {
if (!editor || editor.isDestroyed) return
try {
// 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;