deltaqin
2023-11-06 11:03:22 阅读:1327
bytemd掘金同款markdown编辑器vue配置踩坑指南 Vgplay 2022-01-05
阅读6分钟 前言
为什么使用内容。看了掘金的编辑器,感觉很不错,于是开始了搜索发现使用的是bytemd的,于是开始了查看资料,在自己的项目去配置使用!下面就放上项目官方地址和demo
Github地址:Github
官方demo:demo演示
踩坑过程
do'w下载安装vue里使用 npm install @bytemd/vue -S (或者使用yarn) yarn add @bytemd/vue -S
vue文件里面使用
<template>
<div>
<Editor class="editos" :value="value" />
<Viewer class="viewer" :tabindex="2" :value="value"
></Viewer>
</div>
</template>
安装插件 github文档的官网有插件介绍,大家可以安装需求安装,也可以全部安装
Heading | |
---|---|
graph TD
Start --> Stop
23.png
我的建议如果是个人项目那就不需要care 直接全部上它丫的
大家npm安装就可以,接下来继续安装两个一个是主题样式一个是配置中文的,大家去github直接拷贝json文件或者是css也可以。
npm i bytemd -S // 等会配置中文
npm i juejin-markdown-themes -S // 等会配置主题
配置中文 npm i bytemd -S 你也可以直接拷贝这个包下面的json文件
js 代码 import zhHans from 'bytemd/lib/locales/zh_Hans.json' data () { return { zhHans } } 配置图片上传 原本是需要配置插件的,但在最新版已直接集成了,开启的方法也是特别简单!
JS代码 配置点击事件就可以了 async uploadImage (files) { // files 获取的图片文件,这里处理逻辑 console.log('files', files) return [ { title: files.map((i) => i.name), url: 'http' } ] } 这里再配置两个图片代码方便不清楚怎么上传图片的小伙伴们查看
上传代码.png
图片上传逻辑.png
使用方法就是通过uploadImage方法获取二进制文件,然后这个文件直接就可以通过axios或者是其他上传到服务器,然后把返回的url赋值到数组列表里面就可以了。同理,二进制文件流是可以转成base64图片的
配置样式主题 这里卡了我半天,后面知道了就是简简单单引入css文件,我人麻了~ 无语
Markdown 主题: Markdown主题Github地址
import 'juejin-markdown-themes/dist/juejin.min.css' 直接引入就可以使用不同的主题了,这里使用的掘金的,小伙伴们喜欢其他的也可以使用不同风格的!
完整配置代码 这里简单解释一下@bytemd/vue里面导出两个组件
编辑器Editor
阅读者的Viewer
咱们理解简单一点,那就是编辑(Editor)可以修改,增加, (Viewer)阅读只可以看,也就是渲染出你存储的markdow文档!同样的编辑器配置了插件,阅读器也是需要配置的才可以对应渲染出你存储的样式代码
vue3使用bytemd 实现地址: 个人博客
仓库里面包括了前端样式和接口,我现在博客地址后台就是用的这个,还要API接口也开发完成使用的nodejs, 前端是vite+vue3 前端显示 接口地址
官网出了vue3的这个包,但是我安装了。按照之前的引入就发现渲染出来的markdown文件没有样式 ~
image.png
image.png
引用方法就是
import { Viewer } from '@bytemd/vue-next'
vue3的兼容感觉还不是很好,于是就重新封装一下组件实现了渲染效果。
安装配置,发现并不能如vue2那样方便使用 ~ 磕磕绊绊的还是实现了,应该会有更好的实现方法,这里我就抛砖引玉了.
下面代码实现了有样式渲染和目录
编辑模式配置代码:
<Editor class="editos" :value="state.value" :plugins="plugins" :locale="zhHans" @change="handleChange" :uploadImages="uploadImage" />
// js const plugins = [gfm(), highlight(), breaks(), frontmatter(), footnotes(), gemoji(), mediumZoom()] import 'bytemd/dist/index.css' import { Editor } from '@bytemd/vue-next' import gfm from '@bytemd/plugin-gfm' import highlight from '@bytemd/plugin-highlight' import breaks from '@bytemd/plugin-breaks' import footnotes from '@bytemd/plugin-footnotes' import frontmatter from '@bytemd/plugin-frontmatter' import gemoji from '@bytemd/plugin-gemoji' import mediumZoom from '@bytemd/plugin-medium-zoom' import zhHans from 'bytemd/locales/zh_Hans.json' 编辑的导入,区别不大。主要是渲染的时候,引入viewer出现了问题,后面是通过封装组件的方法实现的,
// MdViewer.vue 组件
实现的方法是参考掘金的一位帅哥的方法。只需要传入数据库保存的md文档内容就可以正确渲染出来,然后还配置了目录,基本实现了掘金的目录定位和滚动跳转到,指定位置。
实现的方法和原理就是 获取h1~ h4 标签,滚动监听,和a标签的锚点去实现
目录实现的代码
// html
// css
.tree { width: 100%; min-height: 400px; background-color: $white; padding: 20px; max-height: 70vh; min-height: 10vh; overflow-y: scroll; .directory { @include font-set($font18, #1a1a1a, 400, 1.5); } .menu_content { width: 100%; .tree_list { display: block; @include font-set($font14, #888, 400, 1.3); padding: 10px 0; &:hover { background-color: #f7f8fa; border-radius: 6px; } } .active { position: relative; color: #1e80ff; &::before { content: ''; height: 20px; width: 5px; background: #1e80ff; position: absolute; left: -17px; top: 50%; border-radius: 0 5px 5px 0; transform: translate(-50%, -50%); } } } }
// js 核心代码实现目录定位和滚动监听 import { onMounted, reactive, ref, nextTick } from 'vue'
interface Menu { type: string; txt: string; offsetTop: number; point: string }
const cata = reactive({ menuData: <Menu[]>[], menuState: '', })
/**
h1 h2 h3 h4 标签样式
@param type */ const menuStyle = (type: string) => { let style = {} if (type === 'H2') style = { 'padding-left': 10 + 'px' } if (type === 'H3') style = { 'padding-left': 20 + 'px' } if (type === 'H4') style = { 'padding-left': 30 + 'px' }
return style
}
onMounted(() => { componentDidMount() window.addEventListener('scroll', onScroll, true) })
// 重新实现目录的定位 const componentDidMount = () => { nextTick(() => { getElement(['H1', 'H2', 'H3', 'H4']) }) }
/**
获取标题锚点
参数nodeArr 表示需要解析目录内容的标题
*/
const getElement = (nodeArr: string[]) => {
let nodeInfo: Menu[] = []
const dom: any = document.querySelector('.markdown-body')
// console.log(dom.childNodes)
dom.childNodes.forEach((item: any, key: number) => {
// console.log(item.nodeName)
if (nodeArr.includes(item.nodeName)) {
nodeInfo.push({
type: item.nodeName,
txt: item.innerText,
offsetTop: item.offsetTop,
point: target_${key}
,
})
item.setAttribute('id', target_${key}
)
console.log(item)
}
})
cata.menuData = nodeInfo cata.menuState = nodeInfo[0].txt console.log('nodeInfo', nodeInfo)
}
/**
监听页面开始滚动 */ const onScroll = (e: any) => { // 当前页面滚动的距离 let scrollTop = e.target.documentElement.scrollTop || e.target.body.scrollTop // console.log(scrollTop) //变量windowHeight是可视区的高度 let windowHeight = document.documentElement.clientHeight || document.body.clientHeight //变量scrollHeight是滚动条的总高度 let scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight
let currentmenu = cata.menuData[0].txt // 设置menuState对象默认值第一个标题 for (let item of cata.menuData) { console.log(item.offsetTop) if (scrollTop >= item.offsetTop) { currentmenu = item.txt } else break }
if (currentmenu !== cata.menuState) { cata.menuState = currentmenu }
// 如果到底部,就命中最后一个标题 if (scrollTop + windowHeight === scrollHeight) { console.log('滚动到底部了') cata.menuState = cata.menuData[cata.menuData.length - 1].txt }
}
实现的效果呢,只能说还是不够完美!还需要优化 ~ 不过基本上满足我自己的需求,后续再踩踩试试。
结尾 以上就是我使用Vue去配置使用bytemd这款编辑器时候碰到的问题,记录下来,方便后续查阅读
已更新vue3的踩坑 ~
评论
扫描二维码获取文章详情
更多精彩内容尽在:WWW.ZNGG.NET