vue 将markdown字符串转html、修改主题、生成目录
前言
将 markdown 字符串转成 html 显示出来,同时把目录也提取出来一起显示。可以使用 marked 来读取 markdown 字符串解析成 html
marked官网:https://marked.js.org/
marked
安装
使用 marked 前需要对其进行安装
npm install marked -s
使用
安装好后,在使用到的页面引入使用即可。
<template>
<div>
<div v-html="content"></div>
</div>
</template>
<script>
import { marked } from 'marked'
export default {
data(){
return {
textData: "# JavaScript高级程序设计\n## 内容简介\n 本书是JavaScript经典图书的新版。第4版全面、深入地介绍了JavaScript开发者必须掌握的前端开发技术,涉及JavaScript的基础特性和高级特性。书中详尽讨论了JavaScript的各个方面,从JavaScript的起源开始,逐步讲解到新出现的技术,其中重点介绍ECMAScript和DOM标准。在此基础上,接下来的各章揭示了JavaScript的基本概念,包括类、期约、迭代器、代理,等等。另外,书中深入探讨了客户端检测、事件、动画、表单、错误处理及JSON。本书同时也介绍了近几年来涌现的重要新规范,包括Fetch API、模块、工作者线程、服务线程以及大量新API。\n## 作者简介\n马特·弗里斯比(Matt Frisbie),Stealth Startup公司CTO,曾担任谷歌公司软件工程师,精通前端技术,拥有十余年Web开发经验,除本书外另著有AngularJS等前端主题图书。毕业于伊利诺伊大学厄巴纳-尚佩恩分校。\n## 目录\n### 第 1章 什么是JavaScript 1\n#### 1.1 简短的历史回顾 1\n#### 1.2 JavaScript实现 2\n#### 1.3 JavaScript版本 9\n#### 1.4 小结 10\n### 第 2章 HTML中的JavaScript 11\n#### 2.1 script元素 11\n#### 2.2 行内代码与外部文件 18\n#### 2.3 文档模式 18\n#### 2.4 noscript元素 19\n测试代码\n```language\nvar a = 1;\n\nfunction fun(){\n console.log(11111)\n}\nfun()\nconosole.log(a)\n```\n\n#### 2.5 小结 20\n### 第3章 语言基础 21\n#### 3.1 语法 21\n#### 3.2 关键字与保留字 23\n#### 3.3 变量 24\n#### 3.4 数据类型 30\n#### 3.5 操作符 56\n#### 3.6 语句 73\n#### 3.7 函数 80\n#### 3.8 小结 82\n### 第4章 变量、作用域与内存 83\n#### 4.1 原始值与引用值 83\n#### 4.2 执行上下文与作用域 87\n#### 4.3 垃圾回收 94\n#### 4.4 小结 101"
}
},
computed:{
content(){
return marked(this.textData)
}
}
}
</script>
效果展示

markdown-css
marked 转 html已实现,但是整体的样式效果看起来和在markerdown文档里看的有差别,那是因为还没有引入 markerdown 的样式,接下来需要引入样式
安装
npm install github-markdown-css
使用
导入 github-markdown-css 样式,并绑定样式
import "github-markdown-css"
<div v-html="content" class="markdown-body"></div>
绑定样式后,实现效果:

修改主题
如果还是觉得默认的效果不满意,可以去这里:https://theme.typoraio.cn/ 选择你想要的主题换上去。使用也很简单,选择自己想要的模板,点击下载样式就好了。

以上就是 markdown 字符串转成 html 并显示了,接下来就是获取目录。获取目录视项目情况而定,因为项目需求中需要使用到目录,所以需要生成目录。
生成目录
找资料时,恰好看到了这个博主的文章,生成目录就是借鉴了这个博主,使用到了里面的一些源码:https://segmentfault.com/a/1190000040462508
获取目录
获取文章中 h1-h6 标题,这里我选择使用 jq 获取,速度快
getCatalog() {
const h = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
var elements = $(':header')
let hElements = []
for (const key of elements) {
if (h.indexOf(key.localName) > -1) {
let text
if (key.children && key.children.length) {
text = this.getText(key.children)
} else {
text = key.innerHTML
}
hElements.push({
hLevel: parseInt(key.localName[1]),
text,
id: key.localName,
uuid: key.id,
})
}
}
console.log('hElements:', hElements)
},
getText() {
let result = null
if (!arr.length) return
for (let i = 0; i < arr.length; i++) {
if (arr[i].children && arr[i].children.length) {
result = this.getText(arr[i].children)
} else {
result = arr[i].innerHTML
}
}
return result
},
获取到的数据是这样子的:

完成以上操作后,拿到 hElements 数组,处理数据,方便树形插件显示
toTree(flatArr) {
var tree = []
var copyArr = flatArr.map(function (item) {
return item
})
// 根据指定级别查找该级别的子孙级,并删除掉已经查找到的子孙级
var getChildrenByLevel = function (currentLevelItem, arr, level) {
if (!currentLevelItem) {
return
}
// 将level值转成负数,再进行比较
var minusCurrentLevel = -currentLevelItem.hLevel
var children = []
for (var i = 0, len = arr.length; i < len; i++) {
var levelItem = arr[i]
if (-levelItem.hLevel < minusCurrentLevel) {
children.push(levelItem)
} else {
// 只找最近那些子孙级
break
}
}
// 从数组中删除已经找到的那些子孙级,以免影响到其他子孙级的查找
if (children.length > 0) {
arr.splice(0, children.length)
}
return children
}
var getTree = function (result, arr, level) {
// 首先将数组第一位移除掉,并添加到结果集中
var currentItem = arr.shift()
currentItem.level = level
result.push(currentItem)
while (arr.length > 0) {
if (!currentItem) {
return
}
// 根据当前级别获取它的子孙级
var children = getChildrenByLevel(currentItem, arr, level)
// 如果当前级别没有子孙级则开始下一个
if (children.length == 0) {
currentItem = arr.shift()
currentItem.level = level
if (currentItem) {
result.push(currentItem)
}
continue
}
currentItem.children = []
// 查找到的子孙级继续查找子孙级
getTree(currentItem.children, children, level + 1)
}
}
getTree(tree, copyArr, 1)
return tree
},
最终的实现效果:

代码高亮
文档中的代码部分是没有高亮的,需添加代码高亮。

这里使用到 highlight.js 插件
highlight.js官网地址:https://highlightjs.org/
安装 highlight.js
npm install highlight.js -S
使用
import hljs from 'highlight.js'
//引入一种语法的高亮 【注意】要引入这个css 不然可能会失效
import 'highlight.js/styles/atom-one-light.css'
// 高亮语法
hljs.highlightAll()
效果展示:

点击目录跳转
这里有两种方式:a标签的锚点定位 和 scrollIntoView() 方法
锚点定位
点击后跳转到指定标题,没有动画效果
<a class="anchor" :href="`#${data.uuid}`">
{{ data.text }}
</a>
scrollIntoView() 方法
点击跳转后有平滑效果
<div @click="toDiv(data.uuid)">{{ data.text }}</div>
...
toDiv(uuid) {
document.getElementById(uuid).scrollIntoView({
behavior: 'smooth',
})
},
源码
<template>
<div class="content">
<el-tree class="tree" ref="tree" node-key="uuid" :data="treeData" :props="defaultProps" default-expand-all>
<div class="custom-tree-node" slot-scope="{ node, data }">
<div @click="toDiv(data.uuid)">{{ data.text }}</div>
<!-- <a class="anchor" :href="`#${data.uuid}`">
{{ data.text }}
</a> -->
</div>
</el-tree>
<div v-html="content" class="markdown-body html-content"></div>
</div>
</template>
<script>
import "github-markdown-css"
import hljs from 'highlight.js'
import 'highlight.js/styles/atom-one-light.css' //引入一种语法的高亮
import {
marked
} from 'marked'
export default {
data() {
return {
treeData: [],
defaultProps: {
label: 'text',
children: 'children',
},
textData: "# JavaScript高级程序设计\n## 内容简介\n 本书是JavaScript经典图书的新版。第4版全面、深入地介绍了JavaScript开发者必须掌握的前端开发技术,涉及JavaScript的基础特性和高级特性。书中详尽讨论了JavaScript的各个方面,从JavaScript的起源开始,逐步讲解到新出现的技术,其中重点介绍ECMAScript和DOM标准。在此基础上,接下来的各章揭示了JavaScript的基本概念,包括类、期约、迭代器、代理,等等。另外,书中深入探讨了客户端检测、事件、动画、表单、错误处理及JSON。本书同时也介绍了近几年来涌现的重要新规范,包括Fetch API、模块、工作者线程、服务线程以及大量新API。\n## 作者简介\n马特·弗里斯比(Matt Frisbie),Stealth Startup公司CTO,曾担任谷歌公司软件工程师,精通前端技术,拥有十余年Web开发经验,除本书外另著有AngularJS等前端主题图书。毕业于伊利诺伊大学厄巴纳-尚佩恩分校。\n## 目录\n### 第 1章 什么是JavaScript 1\n#### 1.1 简短的历史回顾 1\n#### 1.2 JavaScript实现 2\n#### 1.3 JavaScript版本 9\n#### 1.4 小结 10\n### 第 2章 HTML中的JavaScript 11\n#### 2.1 script元素 11\n#### 2.2 行内代码与外部文件 18\n#### 2.3 文档模式 18\n#### 2.4 noscript元素 19\n测试代码\n``` javascript\nvar a = 1;\n\nfunction fun(){\n console.log(11111)\n}\nfun()\nconosole.log(a)\n```\n\n#### 2.5 小结 20\n### 第3章 语言基础 21\n#### 3.1 语法 21\n#### 3.2 关键字与保留字 23\n#### 3.3 变量 24\n#### 3.4 数据类型 30\n#### 3.5 操作符 56\n#### 3.6 语句 73\n#### 3.7 函数 80\n#### 3.8 小结 82\n### 第4章 变量、作用域与内存 83\n#### 4.1 原始值与引用值 83\n#### 4.2 执行上下文与作用域 87\n#### 4.3 垃圾回收 94\n#### 4.4 小结 101"
}
},
created() {
this.$nextTick(() => {
this.getCatalog()
hljs.highlightAll()
})
},
computed: {
content() {
return marked(this.textData)
}
},
methods: {
// 根据内容获取目录
getCatalog() {
const h = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
var elements = $(':header')
let hElements = []
for (const key of elements) {
if (h.indexOf(key.localName) > -1) {
let text
if (key.children && key.children.length) {
text = this.getText(key.children)
} else {
text = key.innerHTML
}
hElements.push({
hLevel: parseInt(key.localName[1]),
text,
id: key.localName,
uuid: key.id,
})
}
}
// console.log('hElements:', hElements)
let result = this.toTree(hElements)
this.treeData = result
// 目录默认选中第一个
this.$nextTick(() => {
if (!result) return
this.$refs.tree.setCurrentKey(result[0].uuid)
})
// console.log('result:', result)
},
toTree(flatArr) {
var tree = []
var copyArr = flatArr.map(function(item) {
return item
})
// 根据指定级别查找该级别的子孙级,并删除掉已经查找到的子孙级
var getChildrenByLevel = function(currentLevelItem, arr, level) {
if (!currentLevelItem) {
return
}
// 将level值转成负数,再进行比较
var minusCurrentLevel = -currentLevelItem.hLevel
var children = []
for (var i = 0, len = arr.length; i < len; i++) {
var levelItem = arr[i]
if (-levelItem.hLevel < minusCurrentLevel) {
children.push(levelItem)
} else {
// 只找最近那些子孙级
break
}
}
// 从数组中删除已经找到的那些子孙级,以免影响到其他子孙级的查找
if (children.length > 0) {
arr.splice(0, children.length)
}
return children
}
var getTree = function(result, arr, level) {
// 首先将数组第一位移除掉,并添加到结果集中
var currentItem = arr.shift()
currentItem.level = level
result.push(currentItem)
while (arr.length > 0) {
if (!currentItem) {
return
}
// 根据当前级别获取它的子孙级
var children = getChildrenByLevel(currentItem, arr, level)
// 如果当前级别没有子孙级则开始下一个
if (children.length == 0) {
currentItem = arr.shift()
currentItem.level = level
if (currentItem) {
result.push(currentItem)
}
continue
}
currentItem.children = []
// 查找到的子孙级继续查找子孙级
getTree(currentItem.children, children, level + 1)
}
}
getTree(tree, copyArr, 1)
return tree
},
getText() {
let result = null
if (!arr.length) return
for (let i = 0; i < arr.length; i++) {
if (arr[i].children && arr[i].children.length) {
result = this.getText(arr[i].children)
} else {
result = arr[i].innerHTML
}
}
return result
},
toDiv(uuid) {
document.getElementById(uuid).scrollIntoView({
behavior: 'smooth',
})
},
}
}
</script>
<style>
.content {
display: flex;
/* padding: 30px; */
overflow: hidden;
height: 100vh;
}
.tree {
margin-right: 15px;
overflow-y: auto;
width: 280px;
flex-shrink: 0;
}
.html-content {
overflow-y: auto;
}
</style>
最终效果

感谢这个大佬的分享:https://segmentfault.com/a/1190000040462508
vue 将markdown字符串转html、修改主题、生成目录的更多相关文章
- vue使用marked.js实现markdown转html并提取标题生成目录
html: <template> <div class="wrapper"> <div class="container"> ...
- Eclipse魔法堂:修改主题
一.前言 习惯黑色主题,而Eclipse默认的白底主题显然不是我的菜,下面一起来修改主题吧! 二.主题资源 Eclipse Color Themes(http://eclipsecolorthemes ...
- 【399】jupyter 修改主题
参考:Jupyter 主题更换 参考:Restoring default theme #86 修改主题的方法: 首先在 cmd 上输入 jt -l 选择自己需要的主题,如 jt -t monokai ...
- Android Studio 3.1.2 修改字体(font)大小(size) 及老版本修改主题、字体、颜色 参照地址
Android Studio 3.1.2 修改字体(font)大小(size) 步骤:File-Settings-Editor-Color Scheme-Color Scheme Font-Size ...
- Android Studio 修改主题和字体
打开设置 或 修改主题 修改字体 参考资料 Android Studio主题以及字体修改
- eleemnt-ui修改主题颜色
饿了吗的element-ui使用的是淡蓝色的主题,有时候我们可以自定义主题,官方的文档给我们提供了如何修改主题,介绍的很详细,自己试验过后,觉得很不错,一方面怕忘记,一方面写一写. 方法一是在线生成一 ...
- 在webpack自定义配置antd的按需加载和修改主题色
最近使用antd来做react项目的UI.从antd官网上,在使用create-react-app脚手架搭建项目时步骤如下: (1)添加模块 react-app-rewired, babel-plug ...
- MahApps.Metro扁平化UI控件库(可修改主题色等)
一.名词解释 使用MahApps.Metro扁平化UI控件库,可以使界面呈现更加美观.本文将总结MahApps.Metro的使用方法,及如何自定义修改其主题颜色等. 详细内容可参考官网:https:/ ...
- 「这样玩Hexo」修改主题自定义实现界面和功能的自定义
首发于个人博客 想获得更好的阅读体验,烦请移步⬆️ 前言 作为一个颜党,在换了许多Hexo的主题后,选择了现在使用的fexo主题.但是相比于大多数博主使用的NEXT,fexo还是不够powerful, ...
随机推荐
- Kafka到底有多高可靠?(RNG NB)
在聊Kafka高可靠之前,先在评论区来波RNG NB好不好! 什么叫可靠性? 大家都知道,系统架构有三高:「高性能.高并发和高可用」,三者的重要性不言而喻. 对于任意系统,想要同时满足三高都是一件非常 ...
- Microsoft Office 代码执行漏洞临时防范方法
一.删除ms-msdt URI 注册表 1.按下键盘上的快捷组合键:win键 和 R键,打开运行(也可以在开始菜单打开运行). 2.在运行窗口中输入命令:regedit,点击确定或敲回车键就可以快速打 ...
- 工具分享:清理 Markdown 中没有引用的图片
前言: 之前,我写笔记的工具一直都是 notion,而且没有写博客的习惯.但是一是由于 notion 的服务器在国外,有时候很不稳定:二是由于 notion 的分享很不方便,把笔记分享给别人点开链接之 ...
- .NET C#基础(5):结构体 - 高性能代码的基石
0. 文章目的 本文面向有一定.NET C#基础知识的学习者,介绍C#中结构体定义.使用以及特点. 1. 阅读基础 了解C#基本语法 了解.NET中的栈与托管堆 2. 值类型 2.1 .N ...
- wsl2环境搭建
序言 我电脑配置不高,开虚拟机跑linux总觉得太卡.最近才了解到windows早就上了wsl2--一款较为轻量的虚拟机软件.所以本篇博客偏笔记向,存粹记录以便多次使用. 环境 宿主机windows1 ...
- WinForms拖控件拖到天荒地老
更新记录: 2022年4月15日:本文迁移自Panda666原博客,原发布时间:2021年4月18日. 2022年4月15日:更新自动生成Web CURD工具. 说明 Winforms的控件拖起来是真 ...
- JuiceFS V1.0 RC1 发布,大幅优化 dump/load 命令性能, 深度用户不容错过
各位社区的伙伴, JuiceFS v1.0 RC1 今天正式发布了!这个版本中,最值得关注的是对元数据迁移备份工具 dump/load 的优化. 这个优化需求来自于某个社区重度用户,这个用户在将亿级数 ...
- UiPath鼠标操作图像的介绍和使用
一.鼠标(mouse)操作的介绍 模拟用户使用鼠标操作的一种行为,例如单击,双击,悬浮.根据作用对象的不同我们可以分为对元素的操作.对文本的操作和对图像的操作 二.鼠标对图像的操作在UiPath中的使 ...
- python基础教程:__call__用法
__call__可以使得方法变成可被调用对象:(PS:python中的方法和普通函数有点区别:方法的第一个参数是类实例) 允许一个类的实例像函数一样被调用.实质上说,这意味着 x() 与 x.call ...
- 零基础学Java(3)运算符
运算符 运算符用于连接值.Java提供了一组丰富的算术和逻辑运算符以及数学函数. 算术运算符 在Java中,使用算术运算符+.-.*./表示加.减.乘.除运算.当参与/运算的两个操作数都是整数时,表示 ...