vue 将markdown字符串转html、修改主题、生成目录

  • vue 将markdown字符串转html、修改主题、生成目录已关闭评论
  • 135 次浏览
  • A+
所属分类:Web前端
摘要

将 markdown 字符串转成 html 显示出来,同时把目录也提取出来一起显示。可以使用 marked 来读取 markdown 字符串解析成 html
marked官网:https://marked.js.org/


前言

将 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 1n#### 1.1 简短的历史回顾 1n#### 1.2 JavaScript实现 2n#### 1.3 JavaScript版本 9n#### 1.4 小结 10n### 第 2章 HTML中的JavaScript 11n#### 2.1 script元素 11n#### 2.2 行内代码与外部文件 18n#### 2.3 文档模式 18n#### 2.4 noscript元素 19n测试代码n```languagenvar a = 1;nnfunction fun(){n  console.log(11111)n}nfun()nconosole.log(a)n```nn#### 2.5 小结 20n### 第3章 语言基础 21n#### 3.1 语法 21n#### 3.2 关键字与保留字 23n#### 3.3 变量 24n#### 3.4 数据类型 30n#### 3.5 操作符 56n#### 3.6 语句 73n#### 3.7 函数 80n#### 3.8 小结 82n### 第4章 变量、作用域与内存 83n#### 4.1 原始值与引用值 83n#### 4.2 执行上下文与作用域 87n#### 4.3 垃圾回收 94n#### 4.4 小结 101"      }    },    computed:{      content(){         return marked(this.textData)      }    } } </script> 

效果展示

vue 将markdown字符串转html、修改主题、生成目录

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> 

绑定样式后,实现效果:
vue 将markdown字符串转html、修改主题、生成目录

修改主题

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

以上就是 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 }, 

获取到的数据是这样子的:
vue 将markdown字符串转html、修改主题、生成目录

完成以上操作后,拿到 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 }, 

最终的实现效果:
vue 将markdown字符串转html、修改主题、生成目录

代码高亮

文档中的代码部分是没有高亮的,需添加代码高亮。
vue 将markdown字符串转html、修改主题、生成目录
这里使用到 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() 

效果展示:
vue 将markdown字符串转html、修改主题、生成目录

点击目录跳转

这里有两种方式: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 1n#### 1.1 简短的历史回顾 1n#### 1.2 JavaScript实现 2n#### 1.3 JavaScript版本 9n#### 1.4 小结 10n### 第 2章 HTML中的JavaScript 11n#### 2.1 script元素 11n#### 2.2 行内代码与外部文件 18n#### 2.3 文档模式 18n#### 2.4 noscript元素 19n测试代码n``` javascriptnvar a = 1;nnfunction fun(){n  console.log(11111)n}nfun()nconosole.log(a)n```nn#### 2.5 小结 20n### 第3章 语言基础 21n#### 3.1 语法 21n#### 3.2 关键字与保留字 23n#### 3.3 变量 24n#### 3.4 数据类型 30n#### 3.5 操作符 56n#### 3.6 语句 73n#### 3.7 函数 80n#### 3.8 小结 82n### 第4章 变量、作用域与内存 83n#### 4.1 原始值与引用值 83n#### 4.2 执行上下文与作用域 87n#### 4.3 垃圾回收 94n#### 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> 

最终效果

vue 将markdown字符串转html、修改主题、生成目录

感谢这个大佬的分享:https://segmentfault.com/a/1190000040462508