当前位置: 首页 > news >正文

前端将Markdown文本转换为富文本显示/编辑,并保存为word文件

参考: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格式文字 的组件 -->
<script setup lang="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 = new MarkdownIt({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><!-- 展示状态 --><div class="show-area" v-html="text" ref="showAreaRef"></div>
</template><style scoped lang="scss">
.show-area {width: 100%;word-wrap: break-word;font-size: v-bind(fontSize);
}
</style>

markdown文本放入富文本编辑器、可导出为word组件

<!-- 编辑 后端传来的Markdown格式文字 的组件 -->
<script setup lang="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转为word
import { 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 = new MarkdownIt({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)
})// 以下是编辑状态相关代码
// 编辑器实例,必须用 shallowRef
const editorRef = shallowRef()
// 编辑器页面高度
const editorHeight = computed(() => {return (window.innerHeight - 40) + 'px'
})
// 编辑器编辑部分最小高度
const editorInitHeight = computed(() => {return (window.innerHeight - 70) + 'px'
})
const editArea = ref<HTMLDivElement>()
// 内容 HTML
const 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})
})// mode
const mode = ref<string>('default')const toolbarConfig = {}
const editorConfig = {placeholder: '请输入内容...',scroll: false
}// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {const editor = editorRef.valueif (editor == null) returneditor.destroy()
})const handleCreated = (editor: any) => {editorRef.value = editor // 记录 editor 实例,重要!
}
// 下载为word文档函数
async function exportDoc() {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 = await asBlob(value, { orientation: 'portrait' }) as Blobconst a = document.createElement('a')a.href = window.URL.createObjectURL(data)a.setAttribute('download', `${props.title ? props.title : '知识平台智能生成文档'}.docx`)a.click()// 下载后将标签移除a.remove()
}
// 监听,如果值变动,就调用下载函数,导出为word
watch(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;" /><div class="edit-area" style="border: 1px solid #ccc" ref="editArea"><Editor style="height: auto;margin: 15px 200px 15px 200px;" v-model="valueHtml" :defaultConfig="editorConfig":mode="mode" @onCreated="handleCreated" /></div>
</template><style scoped lang="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>
http://www.lryc.cn/news/379475.html

相关文章:

  • git-shortlog详解
  • 通过MATLAB实现PID控制器,积分分离控制器以及滑模控制器
  • Node.js 渲染三维模型并导出为图片
  • Win11下安装VS2022失败的解决办法
  • 动态规划:基本概念
  • 小山菌_代码随想录算法训练营第二十九天| 455. 分发饼干 、376. 摆动序列、53. 最大子序和
  • 快手可灵大模型开放视频续写功能,可生成最长约3分钟视频
  • 【代码随想录】【算法训练营】【第45天】 [198]打家劫舍 [213]打家劫舍II [337]打家劫舍III
  • python安装目录文件说明----Dlls文件夹
  • java实现持续集成
  • ClickHouse安装与下载22.3.2.2
  • 【Go语言】Gin 框架教程
  • MySQL性能问题诊断方法和常用工具
  • CGFloat转NSString保持原有的精度,末尾不添加0
  • UDS服务——TransferData (0x36)
  • jQuery 基本操作
  • 有玩家在2011年的MacBook上成功运行了Windows XP 还安装了触摸屏
  • 高纯PFA容量瓶PFA试剂瓶在半导体材料的应用
  • AudioSep:从音频中分离出特定声音(人声、笑声、噪音、乐器等)本地一键整合包下载
  • Prompt 提示词工程:翻译提示
  • 【MySQL 的三大日志的作用】
  • 数据库中数据的id生成和算法
  • SystemVerilog Assertion精华知识
  • pdf怎么压缩到2m以内或5m以内的方法
  • Butter Knife 8
  • AMSR/ADEOS-II L1A Raw Observation Counts V003地球表面和大气微波辐射的详细观测数据
  • MySQL之复制(十一)
  • 深入源码设计!Vue3.js核心API——Computed实现原理
  • 驾考小技巧:老北京布鞋!距离高考出分还剩3天,我却看到有些孩子已经拿了“满分”——早读(逆天打工人爬取热门微信文章解读)
  • java-正则表达式 2