pnkx-admin-mongo/pnkx-uniapp/components/unit-markdown/unit-markdown.vue
2024-01-13 13:29:20 +08:00

550 lines
9.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- 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(/&nbsp;/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>