2023-04-07 17:02:29 +08:00

113 lines
3.7 KiB
Vue

<template>
<div @click="onCLick" class="markdown-body" v-html="html"></div>
</template>
<script>
import '../../../../sass/pages/components/dialog-markdown/markdown.less'
import MarkdownIt from 'markdown-it'
import mdKatex from '@traptitech/markdown-it-katex'
import mila from 'markdown-it-link-attributes'
import hljs from 'highlight.js'
export default {
name: "DialogMarkdown",
props: {
text: {
type: String,
default: ''
},
},
data() {
return {
mdi: null,
}
},
mounted() {
this.copyCodeBlock()
},
updated() {
this.copyCodeBlock()
},
computed: {
html() {
if (this.mdi === null) {
const {highlightBlock} = this
this.mdi = new MarkdownIt({
linkify: true,
highlight(code, language) {
const validLang = !!(language && hljs.getLanguage(language))
if (validLang) {
const lang = language ?? ''
return highlightBlock(hljs.highlight(code, {language: lang}).value, lang)
}
return highlightBlock(hljs.highlightAuto(code).value, '')
},
})
this.mdi.use(mila, {attrs: {target: '_blank', rel: 'noopener'}})
this.mdi.use(mdKatex, {blockClass: 'katexmath-block rounded-md p-[10px]', errorColor: ' #cc0000'})
}
return this.formatMsg(this.mdi.render(this.text))
}
},
methods: {
highlightBlock(str, lang = '') {
return `<pre class="code-block-wrapper"><div class="code-block-header"><span class="code-block-header__lang">${lang}</span><span class="code-block-header__copy">${this.$L('复制代码')}</span></div><code class="hljs code-block-body ${lang}">${str}</code></pre>`
},
formatMsg(text) {
const array = text.match(/<img\s+[^>]*?>/g);
if (array) {
array.some(res => {
text = text.replace(res, `<div class="no-size-image-box">${res}</div>`);
})
}
return text
},
copyCodeBlock() {
const codeBlockWrapper = this.$el.querySelectorAll('.code-block-wrapper')
codeBlockWrapper.forEach((wrapper) => {
const copyBtn = wrapper.querySelector('.code-block-header__copy')
const codeBlock = wrapper.querySelector('.code-block-body')
if (copyBtn && codeBlock && copyBtn.getAttribute("data-copy") !== "click") {
copyBtn.setAttribute("data-copy", "click")
copyBtn.addEventListener('click', () => {
if (navigator.clipboard?.writeText)
navigator.clipboard.writeText(codeBlock.textContent ?? '')
else
this.copyText({text: codeBlock.textContent ?? '', origin: true})
})
}
})
},
copyText(options) {
const props = {origin: true, ...options}
let input
if (props.origin)
input = document.createElement('textarea')
else
input = document.createElement('input')
input.setAttribute('readonly', 'readonly')
input.value = props.text
document.body.appendChild(input)
input.select()
if (document.execCommand('copy'))
document.execCommand('copy')
document.body.removeChild(input)
},
onCLick(e) {
this.$emit('click', e)
}
}
}
</script>