Commit a89e497e82829e9f7f26c7df1e42ed0d74e5dd71
Committed by
GitHub
1 parent
0f50e045
fix: markdown深色模式内容区和代码块未适配bug; markdownViewer改为vidtor自带预览模式 (#2023)
* fix(Markdown): 修复深色模式 内容区和代码块 未改变主题bug * perf(Markdown): MarkDown组件示例增加不同功能示例; 切换深色主题按钮 同时改变 内容区和代码块主题 * perf(MarkdownViewer): MarkdownViewer改为vditor自带的预览模式; 同时适配深色模式 Co-authored-by: 苗大 <v.caoshm@yoozoo.com>
Showing
4 changed files
with
125 additions
and
19 deletions
src/components/Markdown/src/Markdown.vue
... | ... | @@ -19,6 +19,7 @@ |
19 | 19 | import { useModalContext } from '../../Modal'; |
20 | 20 | import { useRootSetting } from '/@/hooks/setting/useRootSetting'; |
21 | 21 | import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated'; |
22 | + import { getTheme } from './getTheme'; | |
22 | 23 | |
23 | 24 | type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined; |
24 | 25 | |
... | ... | @@ -46,8 +47,9 @@ |
46 | 47 | if (!inited) { |
47 | 48 | return; |
48 | 49 | } |
49 | - const theme = val === 'dark' ? 'dark' : 'classic'; | |
50 | - instance.getVditor()?.setTheme(theme); | |
50 | + instance | |
51 | + .getVditor() | |
52 | + ?.setTheme(getTheme(val) as any, getTheme(val, 'content'), getTheme(val, 'code')); | |
51 | 53 | }, |
52 | 54 | { |
53 | 55 | immediate: true, |
... | ... | @@ -87,13 +89,22 @@ |
87 | 89 | if (!wrapEl) return; |
88 | 90 | const bindValue = { ...attrs, ...props }; |
89 | 91 | const insEditor = new Vditor(wrapEl, { |
90 | - theme: getDarkMode.value === 'dark' ? 'dark' : 'classic', | |
92 | + // 设置外观主题 | |
93 | + theme: getTheme(getDarkMode.value) as any, | |
91 | 94 | lang: unref(getCurrentLang), |
92 | 95 | mode: 'sv', |
93 | 96 | fullscreen: { |
94 | 97 | index: 520, |
95 | 98 | }, |
96 | 99 | preview: { |
100 | + theme: { | |
101 | + // 设置内容主题 | |
102 | + current: getTheme(getDarkMode.value, 'content'), | |
103 | + }, | |
104 | + hljs: { | |
105 | + // 设置代码块主题 | |
106 | + style: getTheme(getDarkMode.value, 'code'), | |
107 | + }, | |
97 | 108 | actions: [], |
98 | 109 | }, |
99 | 110 | input: (v) => { | ... | ... |
src/components/Markdown/src/MarkdownViewer.vue
1 | 1 | <template> |
2 | - <!-- eslint-disable vue/no-v-html --> | |
3 | - <div v-html="getHtmlData" :class="$props.class" class="markdown-viewer"></div> | |
2 | + <div ref="viewerRef" id="markdownViewer" :class="$props.class"></div> | |
4 | 3 | </template> |
5 | 4 | |
6 | 5 | <script lang="ts" setup> |
7 | - import { computed, defineProps } from 'vue'; | |
8 | - import showdown from 'showdown'; | |
9 | - | |
10 | - const converter = new showdown.Converter(); | |
11 | - converter.setOption('tables', true); | |
6 | + import { defineProps, onBeforeUnmount, onDeactivated, Ref, ref, unref, watch } from 'vue'; | |
7 | + import VditorPreview from 'vditor/dist/method.min'; | |
8 | + import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated'; | |
9 | + import { useRootSetting } from '/@/hooks/setting/useRootSetting'; | |
10 | + import { getTheme } from './getTheme'; | |
12 | 11 | const props = defineProps({ |
13 | 12 | value: { type: String }, |
14 | 13 | class: { type: String }, |
15 | 14 | }); |
16 | - const getHtmlData = computed(() => converter.makeHtml(props.value || '')); | |
17 | -</script> | |
15 | + const viewerRef = ref<ElRef>(null); | |
16 | + const vditorPreviewRef = ref(null) as Ref<Nullable<VditorPreview>>; | |
17 | + const { getDarkMode } = useRootSetting(); | |
18 | + | |
19 | + function init() { | |
20 | + const viewerEl = unref(viewerRef) as HTMLElement; | |
21 | + vditorPreviewRef.value = VditorPreview.preview(viewerEl, props.value, { | |
22 | + mode: getTheme(getDarkMode.value, 'content'), | |
23 | + theme: { | |
24 | + // 设置内容主题 | |
25 | + current: getTheme(getDarkMode.value, 'content'), | |
26 | + }, | |
27 | + hljs: { | |
28 | + // 设置代码块主题 | |
29 | + style: getTheme(getDarkMode.value, 'code'), | |
30 | + }, | |
31 | + }); | |
32 | + } | |
33 | + watch( | |
34 | + () => getDarkMode.value, | |
35 | + (val) => { | |
36 | + VditorPreview.setContentTheme(getTheme(val, 'content')); | |
37 | + VditorPreview.setCodeTheme(getTheme(val, 'code')); | |
38 | + init(); | |
39 | + }, | |
40 | + ); | |
18 | 41 | |
19 | -<style scoped> | |
20 | - .markdown-viewer { | |
21 | - width: 100%; | |
42 | + watch( | |
43 | + () => props.value, | |
44 | + (v, oldValue) => { | |
45 | + v !== oldValue && init(); | |
46 | + }, | |
47 | + ); | |
48 | + | |
49 | + function destroy() { | |
50 | + const vditorInstance = unref(vditorPreviewRef); | |
51 | + if (!vditorInstance) return; | |
52 | + try { | |
53 | + vditorInstance?.destroy?.(); | |
54 | + } catch (error) {} | |
55 | + vditorPreviewRef.value = null; | |
22 | 56 | } |
23 | -</style> | |
57 | + | |
58 | + onMountedOrActivated(init); | |
59 | + | |
60 | + onBeforeUnmount(destroy); | |
61 | + onDeactivated(destroy); | |
62 | +</script> | ... | ... |
src/components/Markdown/src/getTheme.ts
0 → 100644
1 | +/** | |
2 | + * 获取主题类型 深色浅色模式 对应的值 | |
3 | + * @param darkModeVal 深色模式值 | |
4 | + * @param themeMode 主题类型——外观(默认), 内容, 代码块 | |
5 | + */ | |
6 | +export const getTheme = ( | |
7 | + darkModeVal: 'light' | 'dark' | string, | |
8 | + themeMode: 'default' | 'content' | 'code' = 'default', | |
9 | +) => { | |
10 | + const isDark = darkModeVal === 'dark'; | |
11 | + switch (themeMode) { | |
12 | + case 'default': | |
13 | + return isDark ? 'dark' : 'classic'; | |
14 | + case 'content': | |
15 | + return isDark ? 'dark' : 'light'; | |
16 | + case 'code': | |
17 | + return isDark ? 'dracula' : 'github'; | |
18 | + } | |
19 | +}; | ... | ... |
src/views/demo/editor/markdown/index.vue
... | ... | @@ -28,16 +28,53 @@ |
28 | 28 | setup() { |
29 | 29 | const markDownRef = ref<Nullable<MarkDownActionType>>(null); |
30 | 30 | const valueRef = ref(` |
31 | -# title | |
31 | +# 标题h1 | |
32 | 32 | |
33 | -# content | |
33 | +##### 标题h5 | |
34 | + | |
35 | +**加粗** | |
36 | +*斜体* | |
37 | +~~删除线~~ | |
38 | +[链接](https://github.com/vbenjs/vue-vben-admin) | |
39 | +↓分割线↓ | |
40 | + | |
41 | +--- | |
42 | + | |
43 | + | |
44 | +* 无序列表1 | |
45 | + * 无序列表1.1 | |
46 | + | |
47 | +1. 有序列表1 | |
48 | +2. 有序列表2 | |
49 | + | |
50 | +* [ ] 任务列表1 | |
51 | +* [x] 任务列表2 | |
52 | + | |
53 | +> 引用示例 | |
54 | + | |
55 | +\`\`\`js | |
56 | +// 代码块: | |
57 | +(() => { | |
58 | + var htmlRoot = document.getElementById('htmlRoot'); | |
59 | + var theme = window.localStorage.getItem('__APP__DARK__MODE__'); | |
60 | + if (htmlRoot && theme) { | |
61 | + htmlRoot.setAttribute('data-theme', theme); | |
62 | + theme = htmlRoot = null; | |
63 | + } | |
64 | +})(); | |
65 | +\`\`\` | |
66 | + | |
67 | +| 表格 | 示例 | 🎉️ | | |
68 | +| --- | --- | --- | | |
69 | +| 1 | 2 | 3 | | |
70 | +| 4 | 5 | 6 | | |
34 | 71 | `); |
35 | 72 | |
36 | 73 | function toggleTheme() { |
37 | 74 | const markDown = unref(markDownRef); |
38 | 75 | if (!markDown) return; |
39 | 76 | const vditor = markDown.getVditor(); |
40 | - vditor.setTheme('dark'); | |
77 | + vditor.setTheme('dark', 'dark', 'dracula'); | |
41 | 78 | } |
42 | 79 | |
43 | 80 | function handleChange(v: string) { | ... | ... |