markdown-it能够将markdown语法的内容转换为html内容,这样我们使用markdown语法写的笔记,就可以转换作为网页使用了
Markdown语法
Markdown语法图文全面详解(10分钟学会)
基础使用
安装markdown-it
npm install markdown-it --save 使用markdown-it
可以看到,使用markdown-it,我们把markdown语法的内容转为了html内容。我们发现,md内容中标记的java语言代码会包裹再pre code标签中,并且再highlight函数中回调。。

转化的html文档

<style lang="scss"> .container { width: 600px; margin: 10px auto; textarea { outline: none; } }</style><template> <div class="container"> <textarea v-model="mdContent" rows="6" style="width: 100%;"></textarea> <div v-html="htmlContent"></div> </div></template><script>import MarkdownIt from 'markdown-it'const MarkdownIt2 = require('markdown-it')let md1 = new MarkdownIt()let md2 = new MarkdownIt2()console.log(md1);console.log(md2);console.log(md1.render('# markdown-it rulezz!'));/* h1>markdown-it rulezz!</h1> */console.log(md2.render('# markdown-it rulezz!'));/* h1>markdown-it rulezz!</h1> */const md = new MarkdownIt({ html: true, linkify: true, typographer: true, breaks: true, highlight: function(str, lang) { console.log('str->',str,'lang->',lang); }})export default { name: 'md2Html', data() { return { mdContent:'', htmlContent:'', } }, watch: { mdContent(newVal,oldVal) { this.htmlContent = md.render(newVal) } }}</script> 代码简单高亮1
根据我们前面学到的highlight.js的用法,我们可以这么做,在编辑的时候实时高亮,就是在md转完html,并且渲染完成后,在$nextTick中,高亮对应的html就可以了。

<style lang="scss"> .container { width: 600px; margin: 10px auto; textarea { outline: none; } }</style><template> <div class="container"> <textarea v-model="mdContent" rows="6" style="width: 100%;"></textarea> <div v-html="htmlContent"></div> </div></template><script>import MarkdownIt from 'markdown-it'const MarkdownIt2 = require('markdown-it')import hljs from 'highlight.js'import 'highlight.js/styles/atom-one-dark.css'let md1 = new MarkdownIt()let md2 = new MarkdownIt2()console.log(md1);console.log(md2);console.log(md1.render('# markdown-it rulezz!'));/* h1>markdown-it rulezz!</h1> */console.log(md2.render('# markdown-it rulezz!'));/* h1>markdown-it rulezz!</h1> */const md = new MarkdownIt({ html: true, linkify: true, typographer: true, breaks: true, highlight: function(str, lang) { console.log('str->',str,'lang->',lang); }})export default { name: 'md2Html', data() { return { mdContent:'', htmlContent:'', } }, watch: { mdContent(newVal,oldVal) { this.htmlContent = md.render(newVal) this.$nextTick(()=>{ console.log(333); document.querySelectorAll('pre code').forEach((el) => { hljs.highlightElement(el); }); }) } }}</script> 代码高亮2(学习风宇blog)
添加功能:
- 代码高亮
- 行号
- 一键复制

<style lang="scss">@import url('https://fonts.font.im/css?family=Roboto');* { font-family: 'Roboto';}.container { width: 600px; margin: 10px auto; textarea { outline: none; }}/* 行号样式 */.line-numbers-rows { position: absolute; pointer-events: none; top: 18px; font-size: 100%; left: 0.5em; width: 2.1em; letter-spacing: -1px; border-right: 1px solid #0e0f12; -webkit-user-select: none; -moz-user-select: none; user-select: none; background-color: #282c34;}pre { position: relative; padding-left: 2.6em; line-height: 1.3em;}.line-numbers-rows>span { display: block; counter-increment: linenumber;}pre { background-color: #282c34; border-radius: 8px;}pre code { border-radius: 8px;}.line-numbers-rows>span:before { content: counter(linenumber); color: #999; display: block; padding-right: 0.8em; text-align: right;}.language-name { position: absolute; top: 9px; color: #999999; right: 43px; font-size: 0.8em; -webkit-user-select: none; -moz-user-select: none; user-select: none;}.copy-btn { position: absolute; right: 8px; top: 8px; background-color: #525252; border: none; padding: 3px 6px; border-radius: 3px; color: #cccccc; cursor: pointer; display: none;}pre:hover .copy-btn { display: block;}.copy-textarea { position: absolute; left: -9999px; top: -9999px;}</style><template> <div class="container"> <textarea v-model="mdContent" rows="6" style="width: 100%;"></textarea> <div v-html="htmlContent"></div> </div></template><script>import { getArticle } from '@/api/articleApi'import ClipboardJS from 'clipboard'console.log(ClipboardJS);import MarkdownIt from 'markdown-it'const MarkdownIt2 = require('markdown-it')import hljs from 'highlight.js'import 'highlight.js/styles/atom-one-dark.css'let md1 = new MarkdownIt()let md2 = new MarkdownIt2()console.log(md1);console.log(md2);console.log(md1.render('# markdown-it rulezz!'));/* h1>markdown-it rulezz!</h1> */console.log(md2.render('# markdown-it rulezz!'));/* h1>markdown-it rulezz!</h1> */const md = new MarkdownIt({ html: true, linkify: true, typographer: true, breaks: true, highlight: function (str, lang) { /* str-> @Configuration @EnableWebMvc @EnableGlobalMethodSecurity(prePostEnabled = true) // 因为要控制controller中的方法访问,所以此注解要加到子容器中 @ComponentScan(basePackages = "com.zzhua.controller", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Service.class)}) public class MyWebConfig implements WebMvcConfigurer { @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { // 开启静态资源访问 configurer.enable(); } } lang-> java {name: 'Java', aliases: Array(1), keywords: {…}, illegal: /<//|#/, contains: Array(23), …} */ console.log('str->', str, 'lang->', lang, hljs.getLanguage('java')); /* <span class="hljs-meta">@Configuration</span> <span class="hljs-meta">@EnableWebMvc</span> <span class="hljs-meta">@EnableGlobalMethodSecurity(prePostEnabled = true)</span> <span class="hljs-comment">// 因为要控制controller中的方法访问,所以此注解要加到子容器中</span> <span class="hljs-meta">@ComponentScan(basePackages = "com.zzhua.controller", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Service.class)})</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">MyWebConfig</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">WebMvcConfigurer</span> { <span class="hljs-meta">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">configureDefaultServletHandling</span><span class="hljs-params">(DefaultServletHandlerConfigurer configurer)</span> { <span class="hljs-comment">// 开启静态资源访问</span> configurer.enable(); } } */ console.log(hljs.highlight(str, { language: lang }).value); if (lang && hljs.getLanguage(lang)) { try { let highlightedHtml = hljs.highlight(str, { language: lang }).value // 生成行号 let lineNum = highlightedHtml.split('/n').length - 1 let lineNumbersRowsStart = `<span aria-hidden="true" class="line-numbers-rows">` let lineNumbersRowsEnd = `</span>` for (let i = 0; i < lineNum; i++) { lineNumbersRowsStart += `<span></span>` } const lineNumbersRows = lineNumbersRowsStart + lineNumbersRowsEnd let languageName = `<b class="language-name">${lang}</b>` // 当前时间加随机数生成唯一的id标识 var d = new Date().getTime(); if (window.performance && typeof window.performance.now === "function") { d += performance.now(); } const codeIndex = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace( /[xy]/g, function (c) { var r = (d + Math.random() * 16) % 16 | 0; d = Math.floor(d / 16); return (c == "x" ? r : (r & 0x3) | 0x8).toString(16); } ); // 复制功能需要一个textarea(这个id需要前面加个字母啥的,不能以数字开头) let textAreaHtml = `<textarea class="copy-textarea" id="copy${codeIndex}">${str}</textarea>` let copyButton = `<button class="copy-btn iconfont icon-fuzhi" data-clipboard-action="copy" data-clipboard-target="#copy${codeIndex}" type="button"></button>` /* 如果返回的不含pre code标签,它会自己加上;如果返回的含有pre code标签,它就不加了 */ return `<pre><code class="language-${lang} hljs">${highlightedHtml}</code>${lineNumbersRows}${languageName}${copyButton}${textAreaHtml}</pre>`; } catch (__) { } } return "" }})export default { name: 'md2Html', data() { return { mdContent: '', htmlContent: '', } }, mounted() { getArticle(29).then(data => { this.mdContent = data.mdContent }) }, watch: { mdContent(newVal, oldVal) { let _this = this this.htmlContent = md.render(newVal) this.$nextTick(() => { var clipboard = new ClipboardJS('.copy-btn'); clipboard.on('success', function (e) { console.info('Action:', e.action); console.info('Text:', e.text); console.info('Trigger:', e.trigger); _this.$toast('success','复制成功了哦'); e.clearSelection(); }); clipboard.on('error', function (e) { console.error('Action:', e.action); console.error('Trigger:', e.trigger); }); }) } }}</script> markdown-it 扩展插件
有些markdown语法,在没有装插件之前不能正常显示,需要安装插件后,才能正确显示。
使用示例
需要安装插件,安装命令在后面
import MarkdownIt from 'markdown-it'let md1 = new MarkdownIt()console.log('未用markdown-it-sub时: ', md1.render('H~2~0')); /* 未用markdown-it-sub时: <p>H~2~0</p> */const md3 = new MarkdownIt().use(require('markdown-it-sub'))console.log('使用markdown-it-sub时: ', md3.render('H~2~0')); /* 使用markdown-it-sub时: <p>H<sub>2</sub>0</p> */console.log(md3.render('Hello from mars :satellite:'));md3.use(require('markdown-it-emoji')) /* <p>Hello from mars :satellite:</p> */console.log(md3.render('Hello from mars :satellite:'));/* <p>Hello from mars 📡</p> */ 代码

安装插件
npm i markdown-it-sub markdown-it-sup markdown-it-mark markdown-it-abbr markdown-it-container markdown-it-deflist markdown-it-emoji markdown-it-footnote markdown-it-ins markdown-it-katex-external markdown-it-task-lists --save <style lang="scss">@import url('https://fonts.font.im/css?family=Roboto');* { font-family: 'Roboto';}.container { width: 600px; margin: 10px auto; textarea { outline: none; }}/* 行号样式 */.line-numbers-rows { position: absolute; pointer-events: none; top: 18px; font-size: 100%; left: 0.5em; width: 2.1em; letter-spacing: -1px; border-right: 1px solid #0e0f12; -webkit-user-select: none; -moz-user-select: none; user-select: none; background-color: #282c34;}pre { position: relative; padding-left: 2.6em; line-height: 1.3em;}.line-numbers-rows>span { display: block; counter-increment: linenumber;}pre { background-color: #282c34; border-radius: 8px;}pre code { border-radius: 8px;}.line-numbers-rows>span:before { content: counter(linenumber); color: #999; display: block; padding-right: 0.8em; text-align: right;}.language-name { position: absolute; top: 9px; color: #999999; right: 43px; font-size: 0.8em; -webkit-user-select: none; -moz-user-select: none; user-select: none;}.copy-btn { position: absolute; right: 8px; top: 8px; background-color: #525252; border: none; padding: 3px 6px; border-radius: 3px; color: #cccccc; cursor: pointer; display: none;}pre:hover .copy-btn { display: block;}.copy-textarea { position: absolute; left: -9999px; top: -9999px;}</style><template> <div class="container"> <textarea v-model="mdContent" rows="6" style="width: 100%;"></textarea> <div v-html="htmlContent"></div> </div></template><script>import { getArticle } from '@/api/articleApi'import ClipboardJS from 'clipboard'console.log(ClipboardJS);import MarkdownIt from 'markdown-it'const MarkdownIt2 = require('markdown-it')import hljs from 'highlight.js'import 'highlight.js/styles/atom-one-dark.css'let md1 = new MarkdownIt()let md2 = new MarkdownIt2()console.log(md1);console.log(md2);console.log(md1.render('# markdown-it rulezz!'));/* h1>markdown-it rulezz!</h1> */console.log(md2.render('# markdown-it rulezz!'));/* h1>markdown-it rulezz!</h1> */const md = new MarkdownIt({ html: true, linkify: true, typographer: true, breaks: true, highlight: function (str, lang) { /* str-> @Configuration @EnableWebMvc @EnableGlobalMethodSecurity(prePostEnabled = true) // 因为要控制controller中的方法访问,所以此注解要加到子容器中 @ComponentScan(basePackages = "com.zzhua.controller", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Service.class)}) public class MyWebConfig implements WebMvcConfigurer { @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { // 开启静态资源访问 configurer.enable(); } } lang-> java {name: 'Java', aliases: Array(1), keywords: {…}, illegal: /<//|#/, contains: Array(23), …} */ console.log('str->', str, 'lang->', lang, hljs.getLanguage('java')); /* <span class="hljs-meta">@Configuration</span> <span class="hljs-meta">@EnableWebMvc</span> <span class="hljs-meta">@EnableGlobalMethodSecurity(prePostEnabled = true)</span> <span class="hljs-comment">// 因为要控制controller中的方法访问,所以此注解要加到子容器中</span> <span class="hljs-meta">@ComponentScan(basePackages = "com.zzhua.controller", excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Service.class)})</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">MyWebConfig</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">WebMvcConfigurer</span> { <span class="hljs-meta">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">configureDefaultServletHandling</span><span class="hljs-params">(DefaultServletHandlerConfigurer configurer)</span> { <span class="hljs-comment">// 开启静态资源访问</span> configurer.enable(); } } */ console.log(hljs.highlight(str, { language: lang }).value); if (lang && hljs.getLanguage(lang)) { try { let highlightedHtml = hljs.highlight(str, { language: lang }).value // 生成行号 let lineNum = highlightedHtml.split('/n').length - 1 let lineNumbersRowsStart = `<span aria-hidden="true" class="line-numbers-rows">` let lineNumbersRowsEnd = `</span>` for (let i = 0; i < lineNum; i++) { lineNumbersRowsStart += `<span></span>` } const lineNumbersRows = lineNumbersRowsStart + lineNumbersRowsEnd let languageName = `<b class="language-name">${lang}</b>` // 当前时间加随机数生成唯一的id标识 var d = new Date().getTime(); if (window.performance && typeof window.performance.now === "function") { d += performance.now(); } const codeIndex = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace( /[xy]/g, function (c) { var r = (d + Math.random() * 16) % 16 | 0; d = Math.floor(d / 16); return (c == "x" ? r : (r & 0x3) | 0x8).toString(16); } ); // 复制功能需要一个textarea(这个id需要前面加个字母啥的,不能以数字开头) let textAreaHtml = `<textarea class="copy-textarea" id="copy${codeIndex}">${str}</textarea>` let copyButton = `<button class="copy-btn iconfont icon-fuzhi" data-clipboard-action="copy" data-clipboard-target="#copy${codeIndex}" type="button"></button>` /* 如果返回的不含pre code标签,它会自己加上;如果返回的含有pre code标签,它就不加了 */ return `<pre><code class="language-${lang} hljs">${highlightedHtml}</code>${lineNumbersRows}${languageName}${copyButton}${textAreaHtml}</pre>`; } catch (__) { } } return "" }}) .use(require("markdown-it-sub")) .use(require("markdown-it-sup")) .use(require("markdown-it-mark")) .use(require("markdown-it-abbr")) .use(require("markdown-it-container")) .use(require("markdown-it-deflist")) .use(require("markdown-it-emoji")) .use(require("markdown-it-footnote")) .use(require("markdown-it-ins")) .use(require("markdown-it-katex-external")) .use(require("markdown-it-task-lists"));console.log('未用markdown-it-sub时: ', md1.render('H~2~0')); /* 未用markdown-it-sub时: <p>H~2~0</p> */const md3 = new MarkdownIt() .use(require('markdown-it-sub'))console.log('使用markdown-it-sub时: ', md3.render('H~2~0')); /* 使用markdown-it-sub时: <p>H<sub>2</sub>0</p> */console.log(md3.render('Hello from mars :satellite:'));md3.use(require('markdown-it-emoji')) /* <p>Hello from mars :satellite:</p> */console.log(md3.render('Hello from mars :satellite:'));/* <p>Hello from mars 📡</p> */export default { name: 'md2Html', data() { return { mdContent: '', htmlContent: '', } }, mounted() { getArticle(29).then(data => { this.mdContent = data.mdContent }) }, watch: { mdContent(newVal, oldVal) { let _this = this this.htmlContent = md.render(newVal) this.$nextTick(() => { var clipboard = new ClipboardJS('.copy-btn'); clipboard.on('success', function (e) { console.info('Action:', e.action); console.info('Text:', e.text); console.info('Trigger:', e.trigger); _this.$toast('success','复制成功了哦'); e.clearSelection(); }); clipboard.on('error', function (e) { console.error('Action:', e.action); console.error('Trigger:', e.trigger); }); }) } }}</script> 













