参考:https://www.wangeditor.com/
https://blog.csdn.net/weixin_43797577/article/details/138854324
插件:
markdown-it
@traptitech/markdown-it-katex
markdown-it-link-attributes
highlight.js
@wangeditor/editor
@wangeditor/editor-for-vue
html-docx-js-typescript
markdown展示组件:
<!-- 展示 后端传来的Markdown格式文字 的组件 --><scriptsetuplang="ts">import MarkdownIt from'markdown-it'import mdKatex from'@traptitech/markdown-it-katex'import mila from'markdown-it-link-attributes'import hljs from'highlight.js'import'highlight.js/styles/default.css';import{ ref, computed }from'vue';const props = defineProps<{markdown: string // 父组件传入要展示/编辑的markdown格式文本
fontSize?: string
}>()// 设定文字大小const fontSize = computed<string>(()=>{if(props.fontSize){return props.fontSize
}else{return'16px'}})// 对外暴露innerText,以供复制const showAreaRef =ref()const innerText = computed<string>(()=>{return showAreaRef.value.innerText
})defineExpose({
innerText
})const mdi =newMarkdownIt({linkify:true,highlight:(code: any,lang: any)=>{if(lang && hljs.getLanguage(lang)){return hljs.highlight(code,{language: lang }).value;}else{return hljs.highlightAuto(code).value;}}})
mdi.use(mila,{attrs:{target:'_blank',rel:'noopener'}})
mdi.use(mdKatex,{blockClass:'katexmath-block rounded-md p-[10px]',errorColor:' #cc0000'})const text = computed<string>(()=>{const value = props.markdown ??''// mdi实例将markdown文本渲染成HTML格式文本return mdi.render(value)})</script><template><!-- 展示状态 --><divclass="show-area"v-html="text"ref="showAreaRef"></div></template><stylescopedlang="scss">.show-area{width: 100%;word-wrap: break-word;font-size:v-bind(fontSize);}</style>
markdown文本放入富文本编辑器、可导出为word组件
<!-- 编辑 后端传来的Markdown格式文字 的组件 --><scriptsetuplang="ts">import MarkdownIt from'markdown-it'import mdKatex from'@traptitech/markdown-it-katex'import mila from'markdown-it-link-attributes'import hljs from'highlight.js'import'highlight.js/styles/default.css';import{ ref, computed, onBeforeUnmount, shallowRef, watch, nextTick }from'vue';// WangEditor 相关import'@wangeditor/editor/dist/css/style.css'import{ Editor, Toolbar }from'@wangeditor/editor-for-vue'//将html转为wordimport{ asBlob }from'html-docx-js-typescript'import{ useWriteStore }from'@/stores'import{ storeToRefs }from'pinia'// 是否要导出文档,监听它,只要值改变就导出const{ isExportDoc }=storeToRefs(useWriteStore())const props = defineProps<{markdown: string // 父组件传入要展示/编辑的markdown格式文本
title?: string
}>()// markdown-it 相关const mdi =newMarkdownIt({linkify:true,highlight:(code: any,lang: any)=>{if(lang && hljs.getLanguage(lang)){return hljs.highlight(code,{language: lang }).value;}else{return hljs.highlightAuto(code).value;}}})
mdi.use(mila,{attrs:{target:'_blank',rel:'noopener'}})
mdi.use(mdKatex,{blockClass:'katexmath-block rounded-md p-[10px]',errorColor:' #cc0000'})const text = computed<string>(()=>{const value = props.markdown ??''// mdi实例将markdown文本渲染成HTML格式文本return mdi.render(value)})// 以下是编辑状态相关代码// 编辑器实例,必须用 shallowRefconst editorRef =shallowRef()// 编辑器页面高度const editorHeight =computed(()=>{return(window.innerHeight -40)+'px'})// 编辑器编辑部分最小高度const editorInitHeight =computed(()=>{return(window.innerHeight -70)+'px'})const editArea = ref<HTMLDivElement>()// 内容 HTMLconst valueHtml = ref<string>(text.value)watch(text,(newValue)=>{// 如果newValue为空字符串,说明传输已经结束,writeStore临时存储的文本已被重置,因此编辑器不再接收if(newValue){
valueHtml.value = newValue
}else{// 传输结束,开启新的一行
valueHtml.value +='<p>\n</p>'
ElMessage.success({offset:55,message:'AI撰写完成'})}nextTick(()=>{
editorRef.value.focus(true)// 在内容末尾focus,nextTick确保在内容加载完成后,才让光标focus到末尾
editArea.value!.scrollTop = editArea.value!.scrollHeight
})})// modeconst mode = ref<string>('default')const toolbarConfig ={}const editorConfig ={placeholder:'请输入内容...',scroll:false}// 组件销毁时,也及时销毁编辑器onBeforeUnmount(()=>{const editor = editorRef.value
if(editor ==null)return
editor.destroy()})consthandleCreated=(editor: any)=>{
editorRef.value = editor // 记录 editor 实例,重要!}// 下载为word文档函数asyncfunctionexportDoc(){const editor = editorRef.value
// 将富文本内容拼接为一个完整的htmlconst html = editor.getHtml()const value =`<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>文档</title>
</head>
<body>
${html}
</body>
</html>`// landscape就是横着的,portrait是竖着的,默认是竖屏portrait。const data =awaitasBlob(value,{orientation:'portrait'})as Blob
const a = document.createElement('a')
a.href = window.URL.createObjectURL(data)
a.setAttribute('download',`${props.title ? props.title :'知识平台智能生成文档'}.docx`)
a.click()// 下载后将标签移除
a.remove()}// 监听,如果值变动,就调用下载函数,导出为wordwatch(isExportDoc,()=>{exportDoc()})</script><template><!-- 编辑状态 --><Toolbar:defaultConfig="toolbarConfig":mode="mode":editor="editorRef"style="width: 100%;height: 40px;border-bottom: 1px solid #ccc;position: fixed;z-index: 99;"/><divclass="edit-area"style="border: 1px solid #ccc"ref="editArea"><Editorstyle="height: auto;margin: 15px 200px 15px 200px;"v-model="valueHtml":defaultConfig="editorConfig":mode="mode"@onCreated="handleCreated"/></div></template><stylescopedlang="scss">.edit-area{margin-top: 40px;width: 100%;height:v-bind(editorHeight);overflow-y: auto;:deep(.w-e-text-container){min-height:v-bind(editorInitHeight);}}</style>
版权归原作者 rolling_kitten 所有, 如有侵权,请联系我们删除。