feat: 优化markdown渲染
This commit is contained in:
1 parent
d8a283dd89
commit
63206e71b8
6 files changed
+460
-8
No files matched your search
+1
-1
@@ -1 +1 @@
|
|||||||
v20.18.1
|
v20.15.0
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
<template>
|
||||||
|
<div class="cm-rander-wrapper">
|
||||||
|
<div class="cm-header">
|
||||||
|
<div class="cm-header-title">
|
||||||
|
<span>CodeMirror</span>
|
||||||
|
</div>
|
||||||
|
<div class="cm-header-controls">
|
||||||
|
<div class="cm-switch-show-hide" @click="show = !show">
|
||||||
|
{{ show ? '收起' : '展开' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<miao-collapse :show="show" style="overflow: hidden;">
|
||||||
|
<div ref="cmRootRef"></div>
|
||||||
|
</miao-collapse>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { EditorView, basicSetup } from "codemirror"
|
||||||
|
import { EditorState } from "@codemirror/state"
|
||||||
|
// import chevronDown from "./icons/chevronDown.vue";
|
||||||
|
// import {javascript} from "@codemirror/lang-javascript"
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
data: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const show = ref(true)
|
||||||
|
const cmRootRef = ref<HTMLElement>()
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (!cmRootRef.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
new EditorView({
|
||||||
|
parent: cmRootRef.value,
|
||||||
|
doc: props.data,
|
||||||
|
extensions: [
|
||||||
|
basicSetup,
|
||||||
|
EditorState.readOnly.of(true),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.cm-rander-wrapper {
|
||||||
|
.cm-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 10px;
|
||||||
|
height: 25px;
|
||||||
|
background-color: #000;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 10px 10px 0 0;
|
||||||
|
user-select: none;
|
||||||
|
.cm-header-controls {
|
||||||
|
.cm-switch-show-hide {
|
||||||
|
cursor: pointer;
|
||||||
|
color: #fff;
|
||||||
|
fill: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -2,12 +2,15 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="md-render-wrapper markdown-body">
|
<div class="md-render-wrapper markdown-body">
|
||||||
<div v-html="renderedData" :key="_key"></div>
|
<!-- <div v-html="renderedData" :key="_key"></div> -->
|
||||||
|
<VNodeArr></VNodeArr>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import useMarkdownit from '~/hooks/useMarkdownit';
|
import useMarkdownit from '~/hooks/useMarkdownit';
|
||||||
|
import Html2VNode from '~/utils/html2VNode';
|
||||||
|
import codeMirror from './codeMirror.vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
data: string
|
data: string
|
||||||
@@ -17,17 +20,48 @@ const _key = ref(Math.random())
|
|||||||
|
|
||||||
const markdownIt = await useMarkdownit()
|
const markdownIt = await useMarkdownit()
|
||||||
|
|
||||||
const renderedData = computed(() => {
|
const VNodeArr = computed(() => {
|
||||||
return markdownIt.render(props.data)
|
if (!props.data) {
|
||||||
|
return () => []
|
||||||
|
}
|
||||||
|
const renderedData = markdownIt.render(props.data)
|
||||||
|
const h2v = new Html2VNode()
|
||||||
|
h2v.use(
|
||||||
|
{
|
||||||
|
filter(tagName) {
|
||||||
|
return tagName === 'code'
|
||||||
|
},
|
||||||
|
rander({
|
||||||
|
item,
|
||||||
|
tagName,
|
||||||
|
tagAttrs,
|
||||||
|
middlewareMap
|
||||||
|
}) {
|
||||||
|
return h(
|
||||||
|
codeMirror,
|
||||||
|
{
|
||||||
|
// @ts-ignore
|
||||||
|
data: (item.children[0].children as string).replaceAll('<', '<').replaceAll('>', '>'),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const res = h2v.rander(renderedData)
|
||||||
|
return {
|
||||||
|
setup: () => {
|
||||||
|
return () => res
|
||||||
|
},
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(() => renderedData.value, () => {
|
// watch(() => renderedData.value, () => {
|
||||||
_key.value = Math.random()
|
// _key.value = Math.random()
|
||||||
})
|
// })
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style lang="scss">
|
||||||
.md-render-wrapper {
|
.md-render-wrapper {
|
||||||
code {
|
code {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@@ -39,5 +73,14 @@ watch(() => renderedData.value, () => {
|
|||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
display: block;
|
||||||
|
margin: 0;
|
||||||
|
unicode-bidi: isolate;
|
||||||
|
overflow: hidden;
|
||||||
|
border-style: inset;
|
||||||
|
border-width: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -10,10 +10,13 @@
|
|||||||
"postinstall": "nuxt prepare"
|
"postinstall": "nuxt prepare"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@codemirror/lang-javascript": "^6.2.2",
|
||||||
|
"@codemirror/state": "^6.5.1",
|
||||||
"@pinia/nuxt": "^0.9.0",
|
"@pinia/nuxt": "^0.9.0",
|
||||||
"@types/node": "^22.10.5",
|
"@types/node": "^22.10.5",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"better-sqlite3": "11.3.0",
|
"better-sqlite3": "11.3.0",
|
||||||
|
"codemirror": "^6.0.1",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"markdown-it": "^14.1.0",
|
"markdown-it": "^14.1.0",
|
||||||
|
|||||||
Generated
+149
@@ -8,6 +8,12 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@codemirror/lang-javascript':
|
||||||
|
specifier: ^6.2.2
|
||||||
|
version: 6.2.2
|
||||||
|
'@codemirror/state':
|
||||||
|
specifier: ^6.5.1
|
||||||
|
version: 6.5.1
|
||||||
'@pinia/nuxt':
|
'@pinia/nuxt':
|
||||||
specifier: ^0.9.0
|
specifier: ^0.9.0
|
||||||
version: 0.9.0(magicast@0.3.5)(pinia@2.3.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)))(rollup@4.30.1)
|
version: 0.9.0(magicast@0.3.5)(pinia@2.3.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)))(rollup@4.30.1)
|
||||||
@@ -20,6 +26,9 @@ importers:
|
|||||||
better-sqlite3:
|
better-sqlite3:
|
||||||
specifier: 11.3.0
|
specifier: 11.3.0
|
||||||
version: 11.3.0
|
version: 11.3.0
|
||||||
|
codemirror:
|
||||||
|
specifier: ^6.0.1
|
||||||
|
version: 6.0.1
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.13
|
specifier: ^1.11.13
|
||||||
version: 1.11.13
|
version: 1.11.13
|
||||||
@@ -226,6 +235,30 @@ packages:
|
|||||||
resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==}
|
resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==}
|
||||||
engines: {node: '>=16.13'}
|
engines: {node: '>=16.13'}
|
||||||
|
|
||||||
|
'@codemirror/autocomplete@6.18.4':
|
||||||
|
resolution: {integrity: sha512-sFAphGQIqyQZfP2ZBsSHV7xQvo9Py0rV0dW7W3IMRdS+zDuNb2l3no78CvUaWKGfzFjI4FTrLdUSj86IGb2hRA==}
|
||||||
|
|
||||||
|
'@codemirror/commands@6.8.0':
|
||||||
|
resolution: {integrity: sha512-q8VPEFaEP4ikSlt6ZxjB3zW72+7osfAYW9i8Zu943uqbKuz6utc1+F170hyLUCUltXORjQXRyYQNfkckzA/bPQ==}
|
||||||
|
|
||||||
|
'@codemirror/lang-javascript@6.2.2':
|
||||||
|
resolution: {integrity: sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==}
|
||||||
|
|
||||||
|
'@codemirror/language@6.10.8':
|
||||||
|
resolution: {integrity: sha512-wcP8XPPhDH2vTqf181U8MbZnW+tDyPYy0UzVOa+oHORjyT+mhhom9vBd7dApJwoDz9Nb/a8kHjJIsuA/t8vNFw==}
|
||||||
|
|
||||||
|
'@codemirror/lint@6.8.4':
|
||||||
|
resolution: {integrity: sha512-u4q7PnZlJUojeRe8FJa/njJcMctISGgPQ4PnWsd9268R4ZTtU+tfFYmwkBvgcrK2+QQ8tYFVALVb5fVJykKc5A==}
|
||||||
|
|
||||||
|
'@codemirror/search@6.5.8':
|
||||||
|
resolution: {integrity: sha512-PoWtZvo7c1XFeZWmmyaOp2G0XVbOnm+fJzvghqGAktBW3cufwJUWvSCcNG0ppXiBEM05mZu6RhMtXPv2hpllig==}
|
||||||
|
|
||||||
|
'@codemirror/state@6.5.1':
|
||||||
|
resolution: {integrity: sha512-3rA9lcwciEB47ZevqvD8qgbzhM9qMb8vCcQCNmDfVRPQG4JT9mSb0Jg8H7YjKGGQcFnLN323fj9jdnG59Kx6bg==}
|
||||||
|
|
||||||
|
'@codemirror/view@6.36.2':
|
||||||
|
resolution: {integrity: sha512-DZ6ONbs8qdJK0fdN7AB82CgI6tYXf4HWk1wSVa0+9bhVznCuuvhQtX8bFBoy3dv8rZSQqUd8GvhVAcielcidrA==}
|
||||||
|
|
||||||
'@ctrl/tinycolor@3.6.1':
|
'@ctrl/tinycolor@3.6.1':
|
||||||
resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==}
|
resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -576,11 +609,26 @@ packages:
|
|||||||
'@kwsites/promise-deferred@1.1.1':
|
'@kwsites/promise-deferred@1.1.1':
|
||||||
resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==}
|
resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==}
|
||||||
|
|
||||||
|
'@lezer/common@1.2.3':
|
||||||
|
resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==}
|
||||||
|
|
||||||
|
'@lezer/highlight@1.2.1':
|
||||||
|
resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==}
|
||||||
|
|
||||||
|
'@lezer/javascript@1.4.21':
|
||||||
|
resolution: {integrity: sha512-lL+1fcuxWYPURMM/oFZLEDm0XuLN128QPV+VuGtKpeaOGdcl9F2LYC3nh1S9LkPqx9M0mndZFdXCipNAZpzIkQ==}
|
||||||
|
|
||||||
|
'@lezer/lr@1.4.2':
|
||||||
|
resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==}
|
||||||
|
|
||||||
'@mapbox/node-pre-gyp@2.0.0-rc.0':
|
'@mapbox/node-pre-gyp@2.0.0-rc.0':
|
||||||
resolution: {integrity: sha512-nhSMNprz3WmeRvd8iUs5JqkKr0Ncx46JtPxM3AhXes84XpSJfmIwKeWXRpsr53S7kqPkQfPhzrMFUxSNb23qSA==}
|
resolution: {integrity: sha512-nhSMNprz3WmeRvd8iUs5JqkKr0Ncx46JtPxM3AhXes84XpSJfmIwKeWXRpsr53S7kqPkQfPhzrMFUxSNb23qSA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
'@marijn/find-cluster-break@1.0.2':
|
||||||
|
resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
|
||||||
|
|
||||||
'@netlify/functions@2.8.2':
|
'@netlify/functions@2.8.2':
|
||||||
resolution: {integrity: sha512-DeoAQh8LuNPvBE4qsKlezjKj0PyXDryOFJfJKo3Z1qZLKzQ21sT314KQKPVjfvw6knqijj+IO+0kHXy/TJiqNA==}
|
resolution: {integrity: sha512-DeoAQh8LuNPvBE4qsKlezjKj0PyXDryOFJfJKo3Z1qZLKzQ21sT314KQKPVjfvw6knqijj+IO+0kHXy/TJiqNA==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@@ -1314,6 +1362,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
|
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
codemirror@6.0.1:
|
||||||
|
resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==}
|
||||||
|
|
||||||
color-convert@2.0.1:
|
color-convert@2.0.1:
|
||||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||||
engines: {node: '>=7.0.0'}
|
engines: {node: '>=7.0.0'}
|
||||||
@@ -1380,6 +1431,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==}
|
resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
|
|
||||||
|
crelt@1.0.6:
|
||||||
|
resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
|
||||||
|
|
||||||
croner@9.0.0:
|
croner@9.0.0:
|
||||||
resolution: {integrity: sha512-onMB0OkDjkXunhdW9htFjEhqrD54+M94i6ackoUkjHKbRnXdyEyKRelp4nJ1kAz32+s27jP1FsebpJCVl0BsvA==}
|
resolution: {integrity: sha512-onMB0OkDjkXunhdW9htFjEhqrD54+M94i6ackoUkjHKbRnXdyEyKRelp4nJ1kAz32+s27jP1FsebpJCVl0BsvA==}
|
||||||
engines: {node: '>=18.0'}
|
engines: {node: '>=18.0'}
|
||||||
@@ -2954,6 +3008,9 @@ packages:
|
|||||||
strip-literal@2.1.1:
|
strip-literal@2.1.1:
|
||||||
resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==}
|
resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==}
|
||||||
|
|
||||||
|
style-mod@4.1.2:
|
||||||
|
resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==}
|
||||||
|
|
||||||
stylehacks@7.0.4:
|
stylehacks@7.0.4:
|
||||||
resolution: {integrity: sha512-i4zfNrGMt9SB4xRK9L83rlsFCgdGANfeDAYacO1pkqcE7cRHPdWHwnKZVz7WY17Veq/FvyYsRAU++Ga+qDFIww==}
|
resolution: {integrity: sha512-i4zfNrGMt9SB4xRK9L83rlsFCgdGANfeDAYacO1pkqcE7cRHPdWHwnKZVz7WY17Veq/FvyYsRAU++Ga+qDFIww==}
|
||||||
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
|
engines: {node: ^18.12.0 || ^20.9.0 || >=22.0}
|
||||||
@@ -3411,6 +3468,9 @@ packages:
|
|||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
w3c-keyname@2.2.8:
|
||||||
|
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
|
||||||
|
|
||||||
web-streams-polyfill@3.3.3:
|
web-streams-polyfill@3.3.3:
|
||||||
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
|
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@@ -3698,6 +3758,61 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
mime: 3.0.0
|
mime: 3.0.0
|
||||||
|
|
||||||
|
'@codemirror/autocomplete@6.18.4':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/language': 6.10.8
|
||||||
|
'@codemirror/state': 6.5.1
|
||||||
|
'@codemirror/view': 6.36.2
|
||||||
|
'@lezer/common': 1.2.3
|
||||||
|
|
||||||
|
'@codemirror/commands@6.8.0':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/language': 6.10.8
|
||||||
|
'@codemirror/state': 6.5.1
|
||||||
|
'@codemirror/view': 6.36.2
|
||||||
|
'@lezer/common': 1.2.3
|
||||||
|
|
||||||
|
'@codemirror/lang-javascript@6.2.2':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/autocomplete': 6.18.4
|
||||||
|
'@codemirror/language': 6.10.8
|
||||||
|
'@codemirror/lint': 6.8.4
|
||||||
|
'@codemirror/state': 6.5.1
|
||||||
|
'@codemirror/view': 6.36.2
|
||||||
|
'@lezer/common': 1.2.3
|
||||||
|
'@lezer/javascript': 1.4.21
|
||||||
|
|
||||||
|
'@codemirror/language@6.10.8':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/state': 6.5.1
|
||||||
|
'@codemirror/view': 6.36.2
|
||||||
|
'@lezer/common': 1.2.3
|
||||||
|
'@lezer/highlight': 1.2.1
|
||||||
|
'@lezer/lr': 1.4.2
|
||||||
|
style-mod: 4.1.2
|
||||||
|
|
||||||
|
'@codemirror/lint@6.8.4':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/state': 6.5.1
|
||||||
|
'@codemirror/view': 6.36.2
|
||||||
|
crelt: 1.0.6
|
||||||
|
|
||||||
|
'@codemirror/search@6.5.8':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/state': 6.5.1
|
||||||
|
'@codemirror/view': 6.36.2
|
||||||
|
crelt: 1.0.6
|
||||||
|
|
||||||
|
'@codemirror/state@6.5.1':
|
||||||
|
dependencies:
|
||||||
|
'@marijn/find-cluster-break': 1.0.2
|
||||||
|
|
||||||
|
'@codemirror/view@6.36.2':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/state': 6.5.1
|
||||||
|
style-mod: 4.1.2
|
||||||
|
w3c-keyname: 2.2.8
|
||||||
|
|
||||||
'@ctrl/tinycolor@3.6.1': {}
|
'@ctrl/tinycolor@3.6.1': {}
|
||||||
|
|
||||||
'@element-plus/icons-vue@2.3.1(vue@3.5.13(typescript@5.7.3))':
|
'@element-plus/icons-vue@2.3.1(vue@3.5.13(typescript@5.7.3))':
|
||||||
@@ -3916,6 +4031,22 @@ snapshots:
|
|||||||
|
|
||||||
'@kwsites/promise-deferred@1.1.1': {}
|
'@kwsites/promise-deferred@1.1.1': {}
|
||||||
|
|
||||||
|
'@lezer/common@1.2.3': {}
|
||||||
|
|
||||||
|
'@lezer/highlight@1.2.1':
|
||||||
|
dependencies:
|
||||||
|
'@lezer/common': 1.2.3
|
||||||
|
|
||||||
|
'@lezer/javascript@1.4.21':
|
||||||
|
dependencies:
|
||||||
|
'@lezer/common': 1.2.3
|
||||||
|
'@lezer/highlight': 1.2.1
|
||||||
|
'@lezer/lr': 1.4.2
|
||||||
|
|
||||||
|
'@lezer/lr@1.4.2':
|
||||||
|
dependencies:
|
||||||
|
'@lezer/common': 1.2.3
|
||||||
|
|
||||||
'@mapbox/node-pre-gyp@2.0.0-rc.0':
|
'@mapbox/node-pre-gyp@2.0.0-rc.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
consola: 3.3.3
|
consola: 3.3.3
|
||||||
@@ -3929,6 +4060,8 @@ snapshots:
|
|||||||
- encoding
|
- encoding
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
'@marijn/find-cluster-break@1.0.2': {}
|
||||||
|
|
||||||
'@netlify/functions@2.8.2':
|
'@netlify/functions@2.8.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@netlify/serverless-functions-api': 1.26.1
|
'@netlify/serverless-functions-api': 1.26.1
|
||||||
@@ -4845,6 +4978,16 @@ snapshots:
|
|||||||
|
|
||||||
cluster-key-slot@1.1.2: {}
|
cluster-key-slot@1.1.2: {}
|
||||||
|
|
||||||
|
codemirror@6.0.1:
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/autocomplete': 6.18.4
|
||||||
|
'@codemirror/commands': 6.8.0
|
||||||
|
'@codemirror/language': 6.10.8
|
||||||
|
'@codemirror/lint': 6.8.4
|
||||||
|
'@codemirror/search': 6.5.8
|
||||||
|
'@codemirror/state': 6.5.1
|
||||||
|
'@codemirror/view': 6.36.2
|
||||||
|
|
||||||
color-convert@2.0.1:
|
color-convert@2.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
color-name: 1.1.4
|
color-name: 1.1.4
|
||||||
@@ -4896,6 +5039,8 @@ snapshots:
|
|||||||
crc-32: 1.2.2
|
crc-32: 1.2.2
|
||||||
readable-stream: 4.7.0
|
readable-stream: 4.7.0
|
||||||
|
|
||||||
|
crelt@1.0.6: {}
|
||||||
|
|
||||||
croner@9.0.0: {}
|
croner@9.0.0: {}
|
||||||
|
|
||||||
cronstrue@2.52.0: {}
|
cronstrue@2.52.0: {}
|
||||||
@@ -6676,6 +6821,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
js-tokens: 9.0.1
|
js-tokens: 9.0.1
|
||||||
|
|
||||||
|
style-mod@4.1.2: {}
|
||||||
|
|
||||||
stylehacks@7.0.4(postcss@8.4.49):
|
stylehacks@7.0.4(postcss@8.4.49):
|
||||||
dependencies:
|
dependencies:
|
||||||
browserslist: 4.24.4
|
browserslist: 4.24.4
|
||||||
@@ -7119,6 +7266,8 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.7.3
|
typescript: 5.7.3
|
||||||
|
|
||||||
|
w3c-keyname@2.2.8: {}
|
||||||
|
|
||||||
web-streams-polyfill@3.3.3: {}
|
web-streams-polyfill@3.3.3: {}
|
||||||
|
|
||||||
webidl-conversions@3.0.1: {}
|
webidl-conversions@3.0.1: {}
|
||||||
|
|||||||
@@ -0,0 +1,188 @@
|
|||||||
|
import type { VNode } from "vue";
|
||||||
|
|
||||||
|
// 未完成
|
||||||
|
export default class Html2VNode {
|
||||||
|
private middlewareList: middlewareType[] = []
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.use(this.defaultMiddleware)
|
||||||
|
}
|
||||||
|
|
||||||
|
public use(middleware: middlewareType) {
|
||||||
|
this.middlewareList.push(middleware)
|
||||||
|
}
|
||||||
|
public rander(htmlString: string) {
|
||||||
|
const html2ObjResult = this.html2Obj(htmlString);
|
||||||
|
const middlewareMap = this.buildMiddlewareMap(html2ObjResult);
|
||||||
|
const wrinklesResult = this.wrinkles(html2ObjResult)
|
||||||
|
const vnodes = this.rander2VNode(wrinklesResult, middlewareMap)
|
||||||
|
return vnodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildMiddlewareMap(objs: (TagType | miaoVNodeType)[]) {
|
||||||
|
const tagNameSet = new Set<string>()
|
||||||
|
const middlewareMap = new Map<string, middlewareType>()
|
||||||
|
for (const item of objs) {
|
||||||
|
const { tagName = '' } = this.parseTag(item.tag);
|
||||||
|
tagNameSet.add(tagName)
|
||||||
|
}
|
||||||
|
for (const tagName of tagNameSet) {
|
||||||
|
for (const middleware of this.middlewareList) {
|
||||||
|
if (middleware.filter(tagName)) {
|
||||||
|
middlewareMap.set(tagName, middleware)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return middlewareMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private rander2VNode = (
|
||||||
|
wrinklesResult: (miaoVNodeType | string)[],
|
||||||
|
middlewareMap: Map<string, middlewareType>
|
||||||
|
): (VNode | string)[] => {
|
||||||
|
return wrinklesResult.map((item: miaoVNodeType | string): VNode | string => {
|
||||||
|
if (typeof item === 'string') {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
const { tagName = '', tagAttrs } = this.parseTag(item.tag);
|
||||||
|
return middlewareMap.get(tagName)!.rander({
|
||||||
|
item, tagName, tagAttrs, middlewareMap
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private defaultMiddleware: middlewareType = {
|
||||||
|
filter: (_: string) => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
rander: ({
|
||||||
|
item, tagName, tagAttrs, middlewareMap
|
||||||
|
}) => {
|
||||||
|
if (!tagName) {
|
||||||
|
return item.children as string;
|
||||||
|
}
|
||||||
|
let child: string | (string | VNode)[] = item.children as string
|
||||||
|
if (typeof item.children !== 'string') {
|
||||||
|
child = this.rander2VNode(item.children, middlewareMap)
|
||||||
|
}
|
||||||
|
return h(tagName ?? 'span', tagAttrs, child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private html2Obj = (htmlString: string) => {
|
||||||
|
const html2ObjResult: (TagType | miaoVNodeType)[] = []
|
||||||
|
let currhtml = htmlString;
|
||||||
|
while (true) {
|
||||||
|
const nextTag = this.getNextHtmlTag(currhtml);
|
||||||
|
if (!nextTag) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const middleChild = currhtml.slice(0, nextTag.Index);
|
||||||
|
if (middleChild) {
|
||||||
|
html2ObjResult.push({
|
||||||
|
tag: '',
|
||||||
|
children: middleChild,
|
||||||
|
// html: middleContent
|
||||||
|
})
|
||||||
|
}
|
||||||
|
currhtml = currhtml.slice(nextTag.Index + nextTag.tag.length);
|
||||||
|
html2ObjResult.push(nextTag)
|
||||||
|
}
|
||||||
|
return html2ObjResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
private check = (html2ObjResult: (TagType | miaoVNodeType)[]) => {
|
||||||
|
const stack = []
|
||||||
|
for (const item of html2ObjResult) {
|
||||||
|
if (!item.tag) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
if (item?.isClose && item.isClose == true) {
|
||||||
|
const last = stack.pop();
|
||||||
|
if (last !== this.parseTag(item.tag).tagName) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stack.push(this.parseTag(item.tag).tagName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 想必是flat的反义词吧
|
||||||
|
private wrinkles = (target: (TagType | miaoVNodeType)[]) => {
|
||||||
|
const res: miaoVNodeType[] = []
|
||||||
|
const resStack = [res]
|
||||||
|
for (const item of target) {
|
||||||
|
if (!item.tag) {
|
||||||
|
// @ts-ignore
|
||||||
|
resStack[resStack.length - 1].push(item)
|
||||||
|
// @ts-ignore
|
||||||
|
} else if (item.isClose) {
|
||||||
|
resStack.pop()
|
||||||
|
} else {
|
||||||
|
const _childRes: any = []
|
||||||
|
resStack[resStack.length - 1].push({
|
||||||
|
tag: item.tag,
|
||||||
|
// tag: this.getTagName(item.tag),
|
||||||
|
children: _childRes,
|
||||||
|
})
|
||||||
|
resStack.push(_childRes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getNextHtmlTag = (htmlString: string): {
|
||||||
|
tag: string,
|
||||||
|
Index: number,
|
||||||
|
isClose: boolean
|
||||||
|
} | null => {
|
||||||
|
let startIndex = 0;
|
||||||
|
let tagRegex = /<("[^"]*"|'[^']*'|[^'">])*>/;
|
||||||
|
let tagMatch = tagRegex.exec(htmlString.slice(startIndex));
|
||||||
|
if (tagMatch) {
|
||||||
|
const isClose = tagMatch[0].startsWith('</');
|
||||||
|
return {
|
||||||
|
tag: tagMatch[0],
|
||||||
|
Index: tagMatch.index,
|
||||||
|
isClose
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseTag = (tag: string) => {
|
||||||
|
const tagStr = tag.replace(/<\s*\/*\s*|\s*>/g, '');
|
||||||
|
const tagArr = tagStr.split(' ').filter(item => item.trim());
|
||||||
|
const tagName = tagArr.shift();
|
||||||
|
const tagAttrs = tagArr.map(v => v.trim().split('=')).reduce((pre, cur) => {
|
||||||
|
pre[cur[0]] = cur[1];
|
||||||
|
return pre;
|
||||||
|
}, {} as { [key: string]: string })
|
||||||
|
return { tagName, tagAttrs };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type miaoVNodeType = {
|
||||||
|
tag: string,
|
||||||
|
children: string | miaoVNodeType[],
|
||||||
|
}
|
||||||
|
|
||||||
|
type TagType = {
|
||||||
|
tag: string;
|
||||||
|
Index: number;
|
||||||
|
isClose: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type middlewareType = {
|
||||||
|
filter: (tagName: string) => boolean,
|
||||||
|
rander: (option: {
|
||||||
|
item: miaoVNodeType,
|
||||||
|
tagName: string,
|
||||||
|
tagAttrs: { [key: string]: string },
|
||||||
|
middlewareMap: Map<string, middlewareType>
|
||||||
|
}
|
||||||
|
) => VNode | string
|
||||||
|
}
|
||||||
Reference in new issue
Block a user