550 lines
9.4 KiB
Vue
550 lines
9.4 KiB
Vue
|
<!-- uniapp vue2 markdown解析 -->
|
|||
|
<template>
|
|||
|
<view class="ua__markdown"><rich-text space="nbsp" :nodes="parseNodes(source)"
|
|||
|
@itemclick="handleItemClick"></rich-text></view>
|
|||
|
</template>
|
|||
|
|
|||
|
<script setup>
|
|||
|
import {
|
|||
|
ref,
|
|||
|
computed
|
|||
|
} from 'vue'
|
|||
|
import MarkdownIt from './lib/markdown-it.min.js'
|
|||
|
import hljs from './lib/highlight/uni-highlight.min.js'
|
|||
|
import './lib/highlight/atom-one-dark.css'
|
|||
|
import parseHtml from './lib/html-parser.js'
|
|||
|
|
|||
|
export default {
|
|||
|
|
|||
|
props: {
|
|||
|
source: String,
|
|||
|
showLine: {
|
|||
|
type: [Boolean, String],
|
|||
|
default: true
|
|||
|
}
|
|||
|
},
|
|||
|
data() {
|
|||
|
return {
|
|||
|
markdown: {},
|
|||
|
}
|
|||
|
},
|
|||
|
|
|||
|
created() {
|
|||
|
let copyCodeData = []
|
|||
|
this.markdown = MarkdownIt({
|
|||
|
html: true,
|
|||
|
highlight: function(str, lang) {
|
|||
|
let preCode = ""
|
|||
|
try {
|
|||
|
preCode = hljs.highlightAuto(str).value
|
|||
|
} catch (err) {
|
|||
|
preCode = this.markdown.utils.escapeHtml(str);
|
|||
|
}
|
|||
|
const lines = preCode.split(/\n/).slice(0, -1)
|
|||
|
// 添加自定义行号
|
|||
|
let html = lines.map((item, index) => {
|
|||
|
if (item == '') {
|
|||
|
return ''
|
|||
|
}
|
|||
|
return '<li><span class="line-num" data-line="' + (index + 1) + '"></span>' +
|
|||
|
item + '</li>'
|
|||
|
}).join('')
|
|||
|
if (props.showLine) {
|
|||
|
html = '<ol style="padding: 0px 30px;">' + html + '</ol>'
|
|||
|
} else {
|
|||
|
html = '<ol style="padding: 0px 7px;list-style:none;">' + html + '</ol>'
|
|||
|
}
|
|||
|
copyCodeData.push(str)
|
|||
|
let htmlCode = `<div class="markdown-wrap">`
|
|||
|
// #ifndef MP-WEIXIN
|
|||
|
htmlCode += `<div style="color: #aaa;text-align: right;font-size: 12px;padding:8px;">`
|
|||
|
htmlCode +=
|
|||
|
`${lang}<a class="copy-btn" code-data-index="${copyCodeData.length - 1}" style="margin-left: 8px;">复制代码</a>`
|
|||
|
htmlCode += `</div>`
|
|||
|
// #endif
|
|||
|
htmlCode +=
|
|||
|
`<pre class="hljs" style="padding:10px 8px 0;margin-bottom:5px;overflow: auto;display: block;border-radius: 5px;"><code>${html}</code></pre>`;
|
|||
|
htmlCode += '</div>'
|
|||
|
return htmlCode
|
|||
|
}
|
|||
|
})
|
|||
|
},
|
|||
|
|
|||
|
methods: {
|
|||
|
|
|||
|
parseNodes(value) {
|
|||
|
if (!value) return
|
|||
|
// 解析<br />到\n
|
|||
|
value = value.replace(/<br>|<br\/>|<br \/>/g, "\n")
|
|||
|
value = value.replace(/ /g, " ")
|
|||
|
let htmlString = ''
|
|||
|
if (value.split("```").length % 2) {
|
|||
|
let mdtext = value
|
|||
|
if (mdtext[mdtext.length - 1] != '\n') {
|
|||
|
mdtext += '\n'
|
|||
|
}
|
|||
|
htmlString = this.markdown.render(mdtext)
|
|||
|
} else {
|
|||
|
htmlString = this.markdown.render(value)
|
|||
|
}
|
|||
|
// 解决小程序表格边框型失效问题
|
|||
|
htmlString = htmlString.replace(/<table/g, `<table class="table"`)
|
|||
|
htmlString = htmlString.replace(/<tr/g, `<tr class="tr"`)
|
|||
|
htmlString = htmlString.replace(/<th>/g, `<th class="th">`)
|
|||
|
htmlString = htmlString.replace(/<td/g, `<td class="td"`)
|
|||
|
htmlString = htmlString.replace(/<hr>|<hr\/>|<hr \/>/g, `<hr class="hr">`)
|
|||
|
|
|||
|
// #ifndef APP-NVUE
|
|||
|
return htmlString
|
|||
|
// #endif
|
|||
|
|
|||
|
// 将htmlString转成htmlArray,反之使用rich-text解析
|
|||
|
// #ifdef APP-NVUE
|
|||
|
return parseHtml(htmlString)
|
|||
|
// #endif
|
|||
|
},
|
|||
|
|
|||
|
// 复制代码
|
|||
|
handleItemClick(e) {
|
|||
|
let {
|
|||
|
attrs
|
|||
|
} = e.detail.node
|
|||
|
let {
|
|||
|
"code-data-index": codeDataIndex,
|
|||
|
"class": className
|
|||
|
} = attrs
|
|||
|
if (className == 'copy-btn') {
|
|||
|
uni.setClipboardData({
|
|||
|
data: copyCodeData[codeDataIndex],
|
|||
|
showToast: false,
|
|||
|
success() {
|
|||
|
uni.showToast({
|
|||
|
title: '复制成功',
|
|||
|
icon: 'none'
|
|||
|
});
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
},
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
<style lang="scss" scoped>
|
|||
|
.ua__markdown {
|
|||
|
font-size: 14px;
|
|||
|
line-height: 1.5;
|
|||
|
|
|||
|
h1,
|
|||
|
h2,
|
|||
|
h3,
|
|||
|
h4,
|
|||
|
h5,
|
|||
|
h6 {
|
|||
|
font-family: inherit;
|
|||
|
font-weight: 500;
|
|||
|
line-height: 1.1;
|
|||
|
color: inherit;
|
|||
|
}
|
|||
|
|
|||
|
h1,
|
|||
|
h2,
|
|||
|
h3 {
|
|||
|
margin-top: 20px;
|
|||
|
margin-bottom: 10px
|
|||
|
}
|
|||
|
|
|||
|
h4,
|
|||
|
h5,
|
|||
|
h6 {
|
|||
|
margin-top: 10px;
|
|||
|
margin-bottom: 10px
|
|||
|
}
|
|||
|
|
|||
|
.h1,
|
|||
|
h1 {
|
|||
|
font-size: 36px
|
|||
|
}
|
|||
|
|
|||
|
.h2,
|
|||
|
h2 {
|
|||
|
font-size: 30px
|
|||
|
}
|
|||
|
|
|||
|
.h3,
|
|||
|
h3 {
|
|||
|
font-size: 24px
|
|||
|
}
|
|||
|
|
|||
|
.h4,
|
|||
|
h4 {
|
|||
|
font-size: 18px
|
|||
|
}
|
|||
|
|
|||
|
.h5,
|
|||
|
h5 {
|
|||
|
font-size: 14px
|
|||
|
}
|
|||
|
|
|||
|
.h6,
|
|||
|
h6 {
|
|||
|
font-size: 12px
|
|||
|
}
|
|||
|
|
|||
|
a {
|
|||
|
background-color: transparent;
|
|||
|
color: #2196f3;
|
|||
|
text-decoration: none;
|
|||
|
}
|
|||
|
|
|||
|
hr,
|
|||
|
::v-deep .hr {
|
|||
|
margin-top: 20px;
|
|||
|
margin-bottom: 20px;
|
|||
|
border: 0;
|
|||
|
border-top: 1px solid #e5e5e5;
|
|||
|
}
|
|||
|
|
|||
|
img {
|
|||
|
max-width: 35%;
|
|||
|
}
|
|||
|
|
|||
|
p {
|
|||
|
margin: 0 0 10px
|
|||
|
}
|
|||
|
|
|||
|
em {
|
|||
|
font-style: italic;
|
|||
|
font-weight: inherit;
|
|||
|
}
|
|||
|
|
|||
|
ol,
|
|||
|
ul {
|
|||
|
margin-top: 0;
|
|||
|
margin-bottom: 10px;
|
|||
|
padding-left: 40px;
|
|||
|
}
|
|||
|
|
|||
|
ol ol,
|
|||
|
ol ul,
|
|||
|
ul ol,
|
|||
|
ul ul {
|
|||
|
margin-bottom: 0;
|
|||
|
}
|
|||
|
|
|||
|
ol ol,
|
|||
|
ul ol {
|
|||
|
list-style-type: lower-roman;
|
|||
|
}
|
|||
|
|
|||
|
ol ol ol,
|
|||
|
ul ul ol {
|
|||
|
list-style-type: lower-alpha;
|
|||
|
}
|
|||
|
|
|||
|
dl {
|
|||
|
margin-top: 0;
|
|||
|
margin-bottom: 20px;
|
|||
|
}
|
|||
|
|
|||
|
dt {
|
|||
|
font-weight: 600;
|
|||
|
}
|
|||
|
|
|||
|
dt,
|
|||
|
dd {
|
|||
|
line-height: 1.4;
|
|||
|
}
|
|||
|
|
|||
|
.task-list-item {
|
|||
|
list-style-type: none;
|
|||
|
}
|
|||
|
|
|||
|
.task-list-item input {
|
|||
|
margin: 0 .2em .25em -1.6em;
|
|||
|
vertical-align: middle;
|
|||
|
}
|
|||
|
|
|||
|
pre {
|
|||
|
position: relative;
|
|||
|
z-index: 11;
|
|||
|
}
|
|||
|
|
|||
|
code,
|
|||
|
kbd,
|
|||
|
pre,
|
|||
|
samp {
|
|||
|
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
|||
|
}
|
|||
|
|
|||
|
code:not(.hljs) {
|
|||
|
padding: 2px 4px;
|
|||
|
font-size: 90%;
|
|||
|
color: #c7254e;
|
|||
|
background-color: #ffe7ee;
|
|||
|
border-radius: 4px;
|
|||
|
}
|
|||
|
|
|||
|
code:empty {
|
|||
|
display: none;
|
|||
|
}
|
|||
|
|
|||
|
pre code.hljs {
|
|||
|
color: var(--vg__text-1);
|
|||
|
border-radius: 16px;
|
|||
|
background: var(--vg__bg-1);
|
|||
|
font-size: 12px;
|
|||
|
}
|
|||
|
|
|||
|
.markdown-wrap {
|
|||
|
font-size: 12px;
|
|||
|
margin-bottom: 10px;
|
|||
|
}
|
|||
|
|
|||
|
pre.code-block-wrapper {
|
|||
|
background: #2b2b2b;
|
|||
|
color: #f8f8f2;
|
|||
|
border-radius: 4px;
|
|||
|
overflow-x: auto;
|
|||
|
padding: 1em;
|
|||
|
position: relative;
|
|||
|
}
|
|||
|
|
|||
|
pre.code-block-wrapper code {
|
|||
|
padding: auto;
|
|||
|
font-size: inherit;
|
|||
|
color: inherit;
|
|||
|
background-color: inherit;
|
|||
|
border-radius: 0;
|
|||
|
}
|
|||
|
|
|||
|
.code-block-header__copy {
|
|||
|
font-size: 16px;
|
|||
|
margin-left: 5px;
|
|||
|
}
|
|||
|
|
|||
|
abbr[data-original-title],
|
|||
|
abbr[title] {
|
|||
|
cursor: help;
|
|||
|
border-bottom: 1px dotted #777;
|
|||
|
}
|
|||
|
|
|||
|
blockquote {
|
|||
|
padding: 10px 20px;
|
|||
|
margin: 0 0 20px;
|
|||
|
font-size: 17.5px;
|
|||
|
border-left: 5px solid #e5e5e5;
|
|||
|
}
|
|||
|
|
|||
|
blockquote ol:last-child,
|
|||
|
blockquote p:last-child,
|
|||
|
blockquote ul:last-child {
|
|||
|
margin-bottom: 0
|
|||
|
}
|
|||
|
|
|||
|
blockquote .small,
|
|||
|
blockquote footer,
|
|||
|
blockquote small {
|
|||
|
display: block;
|
|||
|
font-size: 80%;
|
|||
|
line-height: 1.42857143;
|
|||
|
color: #777
|
|||
|
}
|
|||
|
|
|||
|
blockquote .small:before,
|
|||
|
blockquote footer:before,
|
|||
|
blockquote small:before {
|
|||
|
content: '\2014 \00A0'
|
|||
|
}
|
|||
|
|
|||
|
.blockquote-reverse,
|
|||
|
blockquote.pull-right {
|
|||
|
padding-right: 15px;
|
|||
|
padding-left: 0;
|
|||
|
text-align: right;
|
|||
|
border-right: 5px solid #eee;
|
|||
|
border-left: 0
|
|||
|
}
|
|||
|
|
|||
|
.blockquote-reverse .small:before,
|
|||
|
.blockquote-reverse footer:before,
|
|||
|
.blockquote-reverse small:before,
|
|||
|
blockquote.pull-right .small:before,
|
|||
|
blockquote.pull-right footer:before,
|
|||
|
blockquote.pull-right small:before {
|
|||
|
content: ''
|
|||
|
}
|
|||
|
|
|||
|
.blockquote-reverse .small:after,
|
|||
|
.blockquote-reverse footer:after,
|
|||
|
.blockquote-reverse small:after,
|
|||
|
blockquote.pull-right .small:after,
|
|||
|
blockquote.pull-right footer:after,
|
|||
|
blockquote.pull-right small:after {
|
|||
|
content: '\00A0 \2014'
|
|||
|
}
|
|||
|
|
|||
|
.footnotes {
|
|||
|
-moz-column-count: 2;
|
|||
|
-webkit-column-count: 2;
|
|||
|
column-count: 2
|
|||
|
}
|
|||
|
|
|||
|
.footnotes-list {
|
|||
|
padding-left: 2em
|
|||
|
}
|
|||
|
|
|||
|
table,
|
|||
|
::v-deep .table {
|
|||
|
border-spacing: 0;
|
|||
|
border-collapse: collapse;
|
|||
|
width: 100%;
|
|||
|
max-width: 65em;
|
|||
|
overflow: auto;
|
|||
|
margin-top: 0;
|
|||
|
margin-bottom: 16px;
|
|||
|
}
|
|||
|
|
|||
|
table tr,
|
|||
|
::v-deep .table .tr {
|
|||
|
border-top: 1px solid #e5e5e5;
|
|||
|
}
|
|||
|
|
|||
|
table th,
|
|||
|
table td,
|
|||
|
::v-deep .table .th,
|
|||
|
::v-deep .table .td {
|
|||
|
padding: 6px 13px;
|
|||
|
border: 1px solid #e5e5e5;
|
|||
|
}
|
|||
|
|
|||
|
table th,
|
|||
|
::v-deep .table .th {
|
|||
|
font-weight: 600;
|
|||
|
background-color: #eee;
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class*=language-]:before {
|
|||
|
position: absolute;
|
|||
|
z-index: 3;
|
|||
|
top: .8em;
|
|||
|
right: 1em;
|
|||
|
font-size: .8em;
|
|||
|
color: #999;
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-js]:before {
|
|||
|
content: "js"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-ts]:before {
|
|||
|
content: "ts"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-html]:before {
|
|||
|
content: "html"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-md]:before {
|
|||
|
content: "md"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-vue]:before {
|
|||
|
content: "vue"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-css]:before {
|
|||
|
content: "css"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-sass]:before {
|
|||
|
content: "sass"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-scss]:before {
|
|||
|
content: "scss"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-less]:before {
|
|||
|
content: "less"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-stylus]:before {
|
|||
|
content: "stylus"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-go]:before {
|
|||
|
content: "go"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-java]:before {
|
|||
|
content: "java"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-c]:before {
|
|||
|
content: "c"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-sh]:before {
|
|||
|
content: "sh"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-yaml]:before {
|
|||
|
content: "yaml"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-py]:before {
|
|||
|
content: "py"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-docker]:before {
|
|||
|
content: "docker"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-dockerfile]:before {
|
|||
|
content: "dockerfile"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-makefile]:before {
|
|||
|
content: "makefile"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-javascript]:before {
|
|||
|
content: "js"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-typescript]:before {
|
|||
|
content: "ts"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-markup]:before {
|
|||
|
content: "html"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-markdown]:before {
|
|||
|
content: "md"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-json]:before {
|
|||
|
content: "json"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-ruby]:before {
|
|||
|
content: "rb"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-python]:before {
|
|||
|
content: "py"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-bash]:before {
|
|||
|
content: "sh"
|
|||
|
}
|
|||
|
|
|||
|
.hljs[class~=language-php]:before {
|
|||
|
content: "php"
|
|||
|
}
|
|||
|
}
|
|||
|
</style>
|