修复Vditor工具栏显示异常问题
- 在main.ts中添加Vditor CSS样式引入 - 修复ReportDrawer.vue中Vditor配置 - 使用官方文档推荐的完整工具栏配置 - 添加nextTick确保DOM完全渲染 - 修复工具栏pin配置和版本号匹配
This commit is contained in:
parent
1b75c934b3
commit
b635c1fd08
|
|
@ -77,11 +77,11 @@
|
|||
|
||||
<!-- 报告内容 -->
|
||||
<div class="prose max-w-none">
|
||||
<!-- 有内容时显示HTML渲染的内容 -->
|
||||
<!-- 有内容时显示Vditor渲染的Markdown -->
|
||||
<div
|
||||
v-if="props.currentReport?.content && props.currentReport.content.trim()"
|
||||
id="vditor-report-content"
|
||||
class="text-gray-700 leading-relaxed"
|
||||
v-html="getRenderedContent()"
|
||||
></div>
|
||||
|
||||
<!-- 无内容时显示提示信息 -->
|
||||
|
|
@ -163,7 +163,8 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 移除Vditor后不再需要Vue的响应式导入
|
||||
import { ref, watch, onUnmounted, nextTick } from 'vue'
|
||||
import Vditor from 'vditor'
|
||||
|
||||
// Props定义
|
||||
const props = defineProps({
|
||||
|
|
@ -178,6 +179,9 @@ const props = defineProps({
|
|||
// Emits定义
|
||||
const emit = defineEmits(['close', 'navigate', 'get-task-title'])
|
||||
|
||||
// Vditor实例
|
||||
const vditorInstance = ref<Vditor | null>(null)
|
||||
|
||||
// 清理Markdown内容的函数
|
||||
const cleanMarkdownContent = (content: string): string => {
|
||||
if (!content) return ''
|
||||
|
|
@ -192,35 +196,6 @@ const cleanMarkdownContent = (content: string): string => {
|
|||
}
|
||||
|
||||
|
||||
// 简单的Markdown转HTML函数
|
||||
const markdownToHtml = (markdown: string): string => {
|
||||
if (!markdown) return ''
|
||||
|
||||
let html = markdown
|
||||
|
||||
// 标题
|
||||
html = html.replace(/^### (.*$)/gim, '<h3>$1</h3>')
|
||||
html = html.replace(/^## (.*$)/gim, '<h2>$1</h2>')
|
||||
html = html.replace(/^# (.*$)/gim, '<h1>$1</h1>')
|
||||
|
||||
// 粗体和斜体
|
||||
html = html.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
|
||||
html = html.replace(/\*(.*?)\*/g, '<em>$1</em>')
|
||||
|
||||
// 列表
|
||||
html = html.replace(/^- (.*$)/gim, '<li>$1</li>')
|
||||
html = html.replace(/(<li>.*<\/li>)/s, '<ul>$1</ul>')
|
||||
|
||||
// 段落
|
||||
html = html.replace(/\n\n/g, '</p><p>')
|
||||
html = '<p>' + html + '</p>'
|
||||
|
||||
// 清理空段落
|
||||
html = html.replace(/<p><\/p>/g, '')
|
||||
html = html.replace(/<p>\s*<\/p>/g, '')
|
||||
|
||||
return html
|
||||
}
|
||||
|
||||
// 获取清理后的报告内容
|
||||
const getReportContent = () => {
|
||||
|
|
@ -228,13 +203,133 @@ const getReportContent = () => {
|
|||
return cleanMarkdownContent(props.currentReport.content)
|
||||
}
|
||||
|
||||
// 获取渲染后的HTML内容
|
||||
const getRenderedContent = () => {
|
||||
const content = getReportContent()
|
||||
return markdownToHtml(content)
|
||||
// 初始化Vditor(纯预览模式)
|
||||
const initVditor = async () => {
|
||||
// 检查组件是否还存在
|
||||
if (!props.drawerOpen || !props.currentReport) {
|
||||
return
|
||||
}
|
||||
|
||||
// 安全销毁现有实例
|
||||
destroyVditor()
|
||||
|
||||
// 确保DOM元素存在
|
||||
const element = document.getElementById('vditor-report-content')
|
||||
if (!element) {
|
||||
console.error('Vditor容器元素不存在')
|
||||
return
|
||||
}
|
||||
|
||||
// 清空容器内容
|
||||
element.innerHTML = ''
|
||||
|
||||
try {
|
||||
vditorInstance.value = new Vditor('vditor-report-content', {
|
||||
height: 500,
|
||||
toolbar: [
|
||||
'emoji', 'headings', 'bold', 'italic', 'strike', 'link', '|',
|
||||
'list', 'ordered-list', 'check', 'outdent', 'indent', '|',
|
||||
'quote', 'line', 'code', 'inline-code', 'insert-before', 'insert-after', '|',
|
||||
'table', '|', 'undo', 'redo', '|', 'fullscreen', 'edit-mode', '|',
|
||||
'content-theme', 'code-theme', 'export', 'outline', 'preview', 'devtools', 'info', 'help'
|
||||
],
|
||||
toolbarConfig: {
|
||||
pin: true,
|
||||
},
|
||||
cache: {
|
||||
enable: false,
|
||||
},
|
||||
preview: {
|
||||
theme: {
|
||||
current: 'light',
|
||||
path: 'https://unpkg.com/vditor@3.11.2/dist/css/content-theme'
|
||||
}
|
||||
},
|
||||
mode: 'wysiwyg',
|
||||
after: () => {
|
||||
// 再次检查组件状态
|
||||
if (!props.drawerOpen || !props.currentReport) {
|
||||
destroyVditor()
|
||||
return
|
||||
}
|
||||
|
||||
console.log('Vditor初始化完成,工具栏已显示')
|
||||
|
||||
// 设置内容
|
||||
if (vditorInstance.value) {
|
||||
try {
|
||||
vditorInstance.value.setValue(getReportContent())
|
||||
console.log('Vditor内容设置完成')
|
||||
} catch (error) {
|
||||
console.warn('Vditor设置内容失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查工具栏是否正确渲染
|
||||
setTimeout(() => {
|
||||
const vditorElement = document.getElementById('vditor-report-content')
|
||||
if (vditorElement) {
|
||||
const toolbar = vditorElement.querySelector('.vditor-toolbar')
|
||||
const editor = vditorElement.querySelector('.vditor-wysiwyg')
|
||||
const preview = vditorElement.querySelector('.vditor-preview')
|
||||
|
||||
console.log('Vditor元素检查:')
|
||||
console.log('- 工具栏存在:', !!toolbar)
|
||||
console.log('- 编辑器存在:', !!editor)
|
||||
console.log('- 预览存在:', !!preview)
|
||||
|
||||
if (toolbar) {
|
||||
console.log('- 工具栏可见性:', getComputedStyle(toolbar).display)
|
||||
console.log('- 工具栏宽度:', getComputedStyle(toolbar).width)
|
||||
}
|
||||
}
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Vditor初始化失败:', error)
|
||||
vditorInstance.value = null
|
||||
}
|
||||
}
|
||||
|
||||
// 导航和状态信息现在通过props传递
|
||||
// 监听报告变化和抽屉状态
|
||||
watch([() => props.currentReport, () => props.drawerOpen], ([newReport, isOpen]) => {
|
||||
if (isOpen && newReport && newReport.content) {
|
||||
// 使用nextTick确保DOM完全渲染
|
||||
nextTick(() => {
|
||||
if (props.drawerOpen && props.currentReport) {
|
||||
// 再次延迟确保抽屉完全展开
|
||||
setTimeout(() => {
|
||||
if (props.drawerOpen && props.currentReport) {
|
||||
initVditor()
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
})
|
||||
} else if (!isOpen) {
|
||||
// 关闭抽屉时安全销毁Vditor实例
|
||||
destroyVditor()
|
||||
}
|
||||
}, { deep: true })
|
||||
|
||||
// 安全销毁Vditor的函数
|
||||
const destroyVditor = () => {
|
||||
if (vditorInstance.value) {
|
||||
try {
|
||||
vditorInstance.value.destroy()
|
||||
} catch (error) {
|
||||
console.warn('Vditor销毁时出错:', error)
|
||||
} finally {
|
||||
vditorInstance.value = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 组件卸载时清理
|
||||
onUnmounted(() => {
|
||||
destroyVditor()
|
||||
})
|
||||
|
||||
const getTypeClass = (type: string) => {
|
||||
const typeClasses = {
|
||||
|
|
@ -304,7 +399,23 @@ const copyToClipboard = async () => {
|
|||
max-width: none;
|
||||
}
|
||||
|
||||
.prose h1 {
|
||||
/* Vditor样式 */
|
||||
#vditor-report-content {
|
||||
border: none !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
#vditor-report-content :deep(.vditor-preview) {
|
||||
border: none !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
background: transparent !important;
|
||||
font-size: 14px !important;
|
||||
line-height: 1.6 !important;
|
||||
color: #374151 !important;
|
||||
}
|
||||
|
||||
#vditor-report-content :deep(.vditor-preview h1) {
|
||||
font-size: 1.875rem;
|
||||
font-weight: 700;
|
||||
margin-top: 2rem;
|
||||
|
|
@ -312,7 +423,7 @@ const copyToClipboard = async () => {
|
|||
color: #111827;
|
||||
}
|
||||
|
||||
.prose h2 {
|
||||
#vditor-report-content :deep(.vditor-preview h2) {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
margin-top: 1.5rem;
|
||||
|
|
@ -320,7 +431,7 @@ const copyToClipboard = async () => {
|
|||
color: #111827;
|
||||
}
|
||||
|
||||
.prose h3 {
|
||||
#vditor-report-content :deep(.vditor-preview h3) {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin-top: 1.25rem;
|
||||
|
|
@ -328,29 +439,29 @@ const copyToClipboard = async () => {
|
|||
color: #111827;
|
||||
}
|
||||
|
||||
.prose p {
|
||||
#vditor-report-content :deep(.vditor-preview p) {
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1.7;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.prose ul {
|
||||
#vditor-report-content :deep(.vditor-preview ul) {
|
||||
margin-bottom: 1rem;
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
|
||||
.prose li {
|
||||
#vditor-report-content :deep(.vditor-preview li) {
|
||||
margin-bottom: 0.5rem;
|
||||
line-height: 1.6;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.prose strong {
|
||||
#vditor-report-content :deep(.vditor-preview strong) {
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.prose em {
|
||||
#vditor-report-content :deep(.vditor-preview em) {
|
||||
font-style: italic;
|
||||
color: #4b5563;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import App from './App.vue'
|
|||
import './style.css'
|
||||
import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
import 'vditor/dist/index.css'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue