fix: markdown深色模式内容区和代码块未适配bug; markdownViewer改为vidtor自带预览模式 (#2023)
* fix(Markdown): 修复深色模式 内容区和代码块 未改变主题bug * perf(Markdown): MarkDown组件示例增加不同功能示例; 切换深色主题按钮 同时改变 内容区和代码块主题 * perf(MarkdownViewer): MarkdownViewer改为vditor自带的预览模式; 同时适配深色模式 Co-authored-by: 苗大 <v.caoshm@yoozoo.com>
This commit is contained in:
parent
0f50e0458e
commit
a89e497e82
|
|
@ -19,6 +19,7 @@
|
||||||
import { useModalContext } from '../../Modal';
|
import { useModalContext } from '../../Modal';
|
||||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||||
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
|
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
|
||||||
|
import { getTheme } from './getTheme';
|
||||||
|
|
||||||
type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined;
|
type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined;
|
||||||
|
|
||||||
|
|
@ -46,8 +47,9 @@
|
||||||
if (!inited) {
|
if (!inited) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const theme = val === 'dark' ? 'dark' : 'classic';
|
instance
|
||||||
instance.getVditor()?.setTheme(theme);
|
.getVditor()
|
||||||
|
?.setTheme(getTheme(val) as any, getTheme(val, 'content'), getTheme(val, 'code'));
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
immediate: true,
|
immediate: true,
|
||||||
|
|
@ -87,13 +89,22 @@
|
||||||
if (!wrapEl) return;
|
if (!wrapEl) return;
|
||||||
const bindValue = { ...attrs, ...props };
|
const bindValue = { ...attrs, ...props };
|
||||||
const insEditor = new Vditor(wrapEl, {
|
const insEditor = new Vditor(wrapEl, {
|
||||||
theme: getDarkMode.value === 'dark' ? 'dark' : 'classic',
|
// 设置外观主题
|
||||||
|
theme: getTheme(getDarkMode.value) as any,
|
||||||
lang: unref(getCurrentLang),
|
lang: unref(getCurrentLang),
|
||||||
mode: 'sv',
|
mode: 'sv',
|
||||||
fullscreen: {
|
fullscreen: {
|
||||||
index: 520,
|
index: 520,
|
||||||
},
|
},
|
||||||
preview: {
|
preview: {
|
||||||
|
theme: {
|
||||||
|
// 设置内容主题
|
||||||
|
current: getTheme(getDarkMode.value, 'content'),
|
||||||
|
},
|
||||||
|
hljs: {
|
||||||
|
// 设置代码块主题
|
||||||
|
style: getTheme(getDarkMode.value, 'code'),
|
||||||
|
},
|
||||||
actions: [],
|
actions: [],
|
||||||
},
|
},
|
||||||
input: (v) => {
|
input: (v) => {
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,62 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<div ref="viewerRef" id="markdownViewer" :class="$props.class"></div>
|
||||||
<div v-html="getHtmlData" :class="$props.class" class="markdown-viewer"></div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, defineProps } from 'vue';
|
import { defineProps, onBeforeUnmount, onDeactivated, Ref, ref, unref, watch } from 'vue';
|
||||||
import showdown from 'showdown';
|
import VditorPreview from 'vditor/dist/method.min';
|
||||||
|
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
|
||||||
const converter = new showdown.Converter();
|
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||||
converter.setOption('tables', true);
|
import { getTheme } from './getTheme';
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: { type: String },
|
value: { type: String },
|
||||||
class: { type: String },
|
class: { type: String },
|
||||||
});
|
});
|
||||||
const getHtmlData = computed(() => converter.makeHtml(props.value || ''));
|
const viewerRef = ref<ElRef>(null);
|
||||||
</script>
|
const vditorPreviewRef = ref(null) as Ref<Nullable<VditorPreview>>;
|
||||||
|
const { getDarkMode } = useRootSetting();
|
||||||
|
|
||||||
<style scoped>
|
function init() {
|
||||||
.markdown-viewer {
|
const viewerEl = unref(viewerRef) as HTMLElement;
|
||||||
width: 100%;
|
vditorPreviewRef.value = VditorPreview.preview(viewerEl, props.value, {
|
||||||
|
mode: getTheme(getDarkMode.value, 'content'),
|
||||||
|
theme: {
|
||||||
|
// 设置内容主题
|
||||||
|
current: getTheme(getDarkMode.value, 'content'),
|
||||||
|
},
|
||||||
|
hljs: {
|
||||||
|
// 设置代码块主题
|
||||||
|
style: getTheme(getDarkMode.value, 'code'),
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
</style>
|
watch(
|
||||||
|
() => getDarkMode.value,
|
||||||
|
(val) => {
|
||||||
|
VditorPreview.setContentTheme(getTheme(val, 'content'));
|
||||||
|
VditorPreview.setCodeTheme(getTheme(val, 'code'));
|
||||||
|
init();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.value,
|
||||||
|
(v, oldValue) => {
|
||||||
|
v !== oldValue && init();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
function destroy() {
|
||||||
|
const vditorInstance = unref(vditorPreviewRef);
|
||||||
|
if (!vditorInstance) return;
|
||||||
|
try {
|
||||||
|
vditorInstance?.destroy?.();
|
||||||
|
} catch (error) {}
|
||||||
|
vditorPreviewRef.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMountedOrActivated(init);
|
||||||
|
|
||||||
|
onBeforeUnmount(destroy);
|
||||||
|
onDeactivated(destroy);
|
||||||
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
/**
|
||||||
|
* 获取主题类型 深色浅色模式 对应的值
|
||||||
|
* @param darkModeVal 深色模式值
|
||||||
|
* @param themeMode 主题类型——外观(默认), 内容, 代码块
|
||||||
|
*/
|
||||||
|
export const getTheme = (
|
||||||
|
darkModeVal: 'light' | 'dark' | string,
|
||||||
|
themeMode: 'default' | 'content' | 'code' = 'default',
|
||||||
|
) => {
|
||||||
|
const isDark = darkModeVal === 'dark';
|
||||||
|
switch (themeMode) {
|
||||||
|
case 'default':
|
||||||
|
return isDark ? 'dark' : 'classic';
|
||||||
|
case 'content':
|
||||||
|
return isDark ? 'dark' : 'light';
|
||||||
|
case 'code':
|
||||||
|
return isDark ? 'dracula' : 'github';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -28,16 +28,53 @@
|
||||||
setup() {
|
setup() {
|
||||||
const markDownRef = ref<Nullable<MarkDownActionType>>(null);
|
const markDownRef = ref<Nullable<MarkDownActionType>>(null);
|
||||||
const valueRef = ref(`
|
const valueRef = ref(`
|
||||||
# title
|
# 标题h1
|
||||||
|
|
||||||
# content
|
##### 标题h5
|
||||||
|
|
||||||
|
**加粗**
|
||||||
|
*斜体*
|
||||||
|
~~删除线~~
|
||||||
|
[链接](https://github.com/vbenjs/vue-vben-admin)
|
||||||
|
↓分割线↓
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
* 无序列表1
|
||||||
|
* 无序列表1.1
|
||||||
|
|
||||||
|
1. 有序列表1
|
||||||
|
2. 有序列表2
|
||||||
|
|
||||||
|
* [ ] 任务列表1
|
||||||
|
* [x] 任务列表2
|
||||||
|
|
||||||
|
> 引用示例
|
||||||
|
|
||||||
|
\`\`\`js
|
||||||
|
// 代码块:
|
||||||
|
(() => {
|
||||||
|
var htmlRoot = document.getElementById('htmlRoot');
|
||||||
|
var theme = window.localStorage.getItem('__APP__DARK__MODE__');
|
||||||
|
if (htmlRoot && theme) {
|
||||||
|
htmlRoot.setAttribute('data-theme', theme);
|
||||||
|
theme = htmlRoot = null;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
| 表格 | 示例 | 🎉️ |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 1 | 2 | 3 |
|
||||||
|
| 4 | 5 | 6 |
|
||||||
`);
|
`);
|
||||||
|
|
||||||
function toggleTheme() {
|
function toggleTheme() {
|
||||||
const markDown = unref(markDownRef);
|
const markDown = unref(markDownRef);
|
||||||
if (!markDown) return;
|
if (!markDown) return;
|
||||||
const vditor = markDown.getVditor();
|
const vditor = markDown.getVditor();
|
||||||
vditor.setTheme('dark');
|
vditor.setTheme('dark', 'dark', 'dracula');
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleChange(v: string) {
|
function handleChange(v: string) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue