前端读取md,生成对应目录并实现点击标题跳转到指定位置
公司项目需要读取md文件。项目前端实现为vue3+ts,引入的md解析插件为v-md-editer,但是只引入了预览模式,所以没有插件自带的目录功能,需要自己实现。
·
公司项目需要写帮助中心,帮助中心内为用户提供使用手册,需要读取md文件。项目前端实现为vue3+ts,引入的md解析插件为v-md-editer,但是只引入了预览模式,所以没有插件自带的目录功能,需要自己实现。
vue实现读取md:
<el-row>
<el-col :span="6">
<div v-for="anchor in titles" :style="{ padding: `10px 0 10px ${anchor.indent * 20}px` }" @click="handleAnchorClick(anchor)" :key="anchor">
<a style="cursor: pointer">{{ anchor.title }}</a>
</div>
</el-col>
<el-col :span="18" ref="textAreaRef">
<div class="guide-text">
<v-md-preview :text="markDown.text" ref="preview"></v-md-preview>
</div>
</el-col>
</el-row>
页面代理
const { proxy }: any = getCurrentInstance()
ts实现生成目录
const buildDirectory = () => {
// preview为v-md-preview标签绑定的ref
// v-md会将md文件内标题转换为html的h1-h6标签
const anchors = proxy.$refs.preview.$el.querySelectorAll('h1,h2,h3,h4,h5,h6')
titles.value = Array.from(anchors).filter((title: any) => !!title.innerText.trim())
if (!titles.value.length) {
proxy.titles = []
return
}
const hTags = Array.from(new Set(titles.value.map((title: any) => title.tagName))).sort()
proxy.titles = titles.value.map((el: any) => ({
title: el.innerText,
lineIndex: el.getAttribute('data-v-md-line'),
indent: hTags.indexOf(el.tagName)
}))
}
实现目录跳转:
const handleAnchorClick = (anchor: any) => {
const { preview, textAreaRef } = proxy.$refs
const { lineIndex } = anchor
// 目标行位置
const targetPosition = preview.$el.querySelector(`[data-v-md-line="${lineIndex}"]`).getBoundingClientRect().top
// v-md主体位置
const bodyPosition = preview.$el.querySelector('.vuepress-markdown-body').getBoundingClientRect().top
// 以guide-text为父元素,vuepress-markdown-body为子元素进行跳转
textAreaRef.$el.querySelector('.guide-text').scrollTop = targetPosition - bodyPosition
}
跳转这里踩了好几个坑
1.对于html原生标签和引入的插件,获取其元素的方法又一点点差别
以ref为preview为例
原生标签:直接用$refs.preview 获取元素
插件:$refs.preview.$el 获取元素
2.scrollTop方法
- 父,子元素需设置高度,并且子元素高度必须大于父元素,这一点应该很好理解,如果子元素高度始终小于父元素,那么无论怎么设置scrollTop的值都不可能大于0
- 父元素需设置overflow: scroll 或 overflow-y:scroll,设置完这个之后父元素才能顺利的加载出滚动条,并成功的设置滚动高度
更多推荐
已为社区贡献1条内容
所有评论(0)