vue-markdown插件实现markdown文件预览(含目录大纲展示)

vue-markdown插件实现markdown文件显示

Vue-Markdown 是一个轻量级且高效的库,用于在Vue.js应用程序中渲染Markdown文本。它允许开发者以简洁的方式将Markdown的强大功能与Vue组件的灵活性相结合,提升开发效率和用户体验。vue-markdown 是一个基于 marked.js 的 Vue Markdown 插件。它是一个简单易用的 Markdown 解析器,可以方便地将 Markdown 文档解析为 HTML。它有如下特点:

  • 功能强大:支持 Markdown 语法的全部特性,例如标题、列表、链接等。

  • 易于使用:只需要在 Vue 组件中引入 vue-markdown 插件,并使用简单的模板语法即可实现 Markdown 的解析和渲染。

  • 高性能:基于 marked.js,性能优异,可以快速地解析和渲染大量的 Markdown 文档。

  • 扩展性强:支持自定义渲染规则,可以通过插件扩展功能,以满足更多的需求。

一、插件使用

1、插件说明

vue-markdown插件的灵活性较好,支持直接传递Markdown字符串,或者通过绑定数据属性来动态渲染Markdown。此外,还可以自定义渲染规则,扩展或替换特定的Markdown语法,以满足个性化需求。在github上看了作者的源码,发现该插件也引入了markdown-it,并且支持大部分的markdown-it的插件,通过插件的引入即可使用。

官方demo

1)slots

在组件中使用 vue-markdown 插件,可以在模板中添加 slots、props 和 events 的代码,如下:

<template>
  <vue-markdown :source="markdownText" >
    <template v-slot:pre="">
      <p>这是一个自定义的前置处理。</p>
    </template>
    <template v-slot:code="props">
      <pre :class="'language-' + props.language">{{ props.code }}</pre>
    </template>
    <template v-slot:blockquote="">
      <blockquote>{{ props.content }}</blockquote>
    </template>
  </vue-markdown>
</template> 
2)配置参数
参数名称类型默认值描述
watchesArray["source", "show", "toc"]是否开启监视数据变化,自动改变HTML。
sourceStringnull要转换为 HTML 的 Markdown 字符串。
showBooleantrue是否显示转换后的 HTML 内容。
htmlBooleantrue是否允许解析 HTML 标签。默认为 false。
xhtml-outBooleantrue是否输出 XHTML 格式。<br></br> => <br />
breaksBooleantrue是否将换行符解析为 <br/> 标签。\n => <br>
linkifyBooleantrue是否将纯文本链接转换为链接。
emojiBooleantrue是否支持 emoji 表情。
typographerBooleantrue是否开启排版选项,例如引号转换、省略号转换等。
lang-prefixStringlanguage-语法高亮语言前缀。
quotesString“”‘’引用标记。中文: “”‘’, 德文:„“‚‘ ,俄罗斯: «»„“
table-classStringtable表格的 CSS 类名。
task-listsBooleantrue是否支持任务列表。
tocBooleanfalse是否生成目录。
toc-idStringundefined生成目录的Id
toc-classStringtable目录的 CSS 类名。
toc-first-levelNumber2目录最顶层标题的级别,取值范围为 1-6。默认为 2。
toc-last-levelNumber'toc-first-level' + 1目录最后一层标题的级别,取值范围为 1-6。默认为5。
toc-anchor-linkBooleantrue在标题中启用自动锚链接
toc-anchor-classStringtoc-anchor自定义锚类名
toc-anchor-link-symbolString#目录中的锚点链接的符号。默认为 ‘#’。
toc-anchor-link-spaceBooleantrue目录中的锚点链接前的空格。
toc-anchor-link-classStringtoc-anchor-link目录中的锚点链接的 CSS 类名。
anchorAttributesObject{}锚点标签的属性。: '_blank’orrel: ‘nofollow’`
prerenderFunction (String) Stringnull在转换 HTML 前的回调函数。
postrenderFunction (String) Stringnull在转换 HTML 后的回调函数。
3)事件

vue-markdown 插件中,提供了以下两个事件:

方法名称参数描述
rendered显示的html元素(string)渲染结束后触发
toc-rendered目录html元素(string)TOC目录渲染结束后触发,如果toc传的是false则不会触发

2、安装

// npm
npm install vue-markdown
// yarn
yarn add vue-markdown --save

3、使用

<template>
  <div>
    <VueMarkdown :source="markdownText" />
  </div>
</template>

<script>
import VueMarkdown from 'vue-markdown'

export default {
  components: { VueMarkdown },
  data() {
    return {
      markdownText: '# 这是第一个标题!'
    }
  }
}
</script>

二、页面中渲染并添加目录

在实际的项目开发过程中,为了方便定位与查阅,需要目录大纲,我们可以在旁边加上一个目录大纲,这里使用的el-tree进行目录的展示。

1、HTML部分

<template>
	<div class="page-api" id="myElement">
		<vue-markdown id="content" class="api-content" :source="markdownContent"></vue-markdown>
		<div class="api-tree" id="tree">
			<el-tree :data="tree" :default-expand-all="true" @node-click="handleNodeClick"></el-tree>
		</div>
	</div>
</template>

2、JS部分

<script>
import VueMarkdown from 'vue-markdown';
import markdownItAnchor from 'markdown-it-anchor';
import markdownItToc from 'markdown-it-table-of-contents';
import markdownItEmoji from 'markdown-it-emoji';
import markdownItKatex from 'markdown-it-katex';
export default {
	data() {
		return {
			markdown: '# h1 Heading\n ## h2 Heading\n ### h3 Heading',
			markdownContent: '',
			tree: [],
			plugins: [markdownItAnchor, [markdownItToc, { includeLevel: [2, 3] }], markdownItEmoji, markdownItKatex]
		};
	},
	mounted() {
		this.loadMarkdownFile();
	},
	components: {
		VueMarkdown
	},
	methods: {
		async loadMarkdownFile() {
			try {
                //引入在public文件夹下的md文件
				const response = await fetch('/XXXX.md');
				const markdownText = await response.text();
				this.markdownContent = markdownText;
				this.$nextTick(() => {
					this.catalogTree();
				});
			} catch (error) {
				console.error('Failed to load the Markdown file:', error);
			}
		},
		catalogTree() {
			const content = document.getElementById('content').children;
			var arr = [];
			let currentHightestLevel;
			let parentId;
			let index = 0;
			let nodeArr = [];
			let tree = [];
			for (let i = 0; i < content.length; i++) {
				let header = content[i].localName;
				//如果是标题进行下一步
				if (/\b[h][0-9]\b/.test(header)) {
					let ele = content[i]; // 直接使用DOM元素
					let name = ele.textContent; // 获取元素的文本内容
					ele.setAttribute('id', i); // 设置元素的ID
					
					let id = i;
					if (index === 0 || header <= currentHightestLevel) {
						currentHightestLevel = header;
						parentId = id;
					}
					arr.push({
						id: id,
						label: name,
						parentId: parentId == id ? '0' : parentId
					});
					index++;
				}
			}
			arr.forEach((item) => {
				if (item.parentId === '0') {
					tree.push(this.convertArrayToTree(arr, item));
				}
			});
			this.tree = tree;
		},
		convertArrayToTree(arr, node) {
			for (let i = 0; i < arr.length; i++) {
				if (arr[i].parentId === node.id) {
					const res = this.convertArrayToTree(arr, arr[i]);
					if (node.children) {
						node.children.push(res);
					} else {
						node.children = [res];
					}
				}
			}
			return node;
		},
		handleNodeClick(data) {
			let anchorElement = document.getElementById(data.id);

			let scrollPosition = anchorElement.offsetTop - 20;

			let myElement = document.getElementById('myElement');
			myElement.scrollTo({
				left: 0,
				top: scrollPosition,
				behavior: 'smooth'
			});
		}
	}
};
</script>

3、CSS样式

<style>
.page-api {
	display: flex;
	width: 100%;
	height: 100%;
	overflow-y: scroll;
	background-color: #fff;
}
.api-tree {
	position: fixed;
	right: 20px;
	top: 120px;
	width: 250px;
	height: 600px;
	margin-right: 10px;
	overflow-y: scroll;
	/* text-overflow: ellipsis; */
	z-index: 99;
	.el-tree {
		background: none;
		color: #686868;
		.el-tree-node:focus > .el-tree-node__content,
		.el-tree-node__content:hover {
			background: none;
			color: rgb(24, 144, 255);
		}
	}
}
.api-tree::-webkit-scrollbar {
	width: 8px;
}

.api-content {
	flex: 1;
	width: 80%;
	margin-left: 20px;
	margin-right: 220px;
	padding: 0 30px;
	h2 {
		margin-left: 20px;
		margin-bottom: 10px;
	}
	h3 {
		margin-left: 25px;
		margin-bottom: 8px;
	}
	h4 {
		margin-left: 30px;
		margin-bottom: 5px;
	}
	li {
		margin-left: 40px;
	}
	code {
		border-radius: 2px;
		color: #ffaa7f;
		margin: 0 2px;
		padding: 3px 5px;
		white-space: pre-wrap;
	}
	table {
		border-collapse: collapse;
		border-spacing: 0;
		th,
		td {
			border: 1px solid #ddd;
			padding: 6px 13px;
			margin: 0;
		}
	}
	pre {
		background: rgba(0, 0, 0, 0.7);
		padding: 20px 30px;
	}
}
.page-api::-webkit-scrollbar {
	width: 8px;
}
/* 滚动条滑块样式 */
.page-api::-webkit-scrollbar-thumb {
	background-color: #888; /* 设置滑块背景颜色 */
	border-radius: 4px; /* 设置滑块圆角 */
}
</style>

4、效果展示

在这里插入图片描述

如果你的图片也是base64的格式,那么vue-markdown插件将无法满足你的需求,请移步这一篇博客。将详细介绍marked.js的使用,兼容性较好,也很方便。
https://blog.csdn.net/m0_59415345/article/details/140730869?spm=1001.2014.3001.5502

  • 20
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值