办学质量监测教学评价系统
shenrongliang
2025-06-13 11d86cc6c26bb4f709e407acadf4805c2024e79f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<script setup lang="ts">
import type { PropType } from 'vue';
 
import {
  onBeforeUnmount,
  onMounted,
  shallowRef,
  useTemplateRef,
  watch,
} from 'vue';
 
import { usePreferences } from '@vben/preferences';
 
import Vditor from 'vditor';
 
import 'vditor/dist/index.css';
 
const props = defineProps({
  // 编辑器高度
  height: {
    // string或者number类型
    type: [String, Number],
    default: 500,
  },
  /**
   * 编辑模式。默认值: 'wysiwyg'
   * wysiwyg: 所见即所得
   * ir: 即时渲染
   * sv: 分屏预览
   */
  mode: {
    type: String as PropType<'ir' | 'sv' | 'wysiwyg'>,
    default: 'wysiwyg',
  },
  // 编辑器唯一ID 缓存使用 可记录上次输入
  id: {
    type: String,
    required: false,
    default: '',
    validator(value, props) {
      if (!value && props.enableCache) {
        console.warn('The id is required when enableCache is true');
        return false;
      }
      return true;
    },
  },
  enableCache: {
    type: Boolean,
    default: false,
  },
  // 禁用编辑器
  disabled: {
    type: Boolean,
    default: false,
  },
  // 其他配置项
  options: {
    type: Object as PropType<IOptions>,
    default: () => ({}),
  },
});
 
const emit = defineEmits<{
  // 初始化 cdn加载完成
  mounted: [];
}>();
 
// 挂载节点
const vditorRef = useTemplateRef('vditorRef');
// 编辑器实例
const vditorInstance = shallowRef<null | Vditor>(null);
 
// 监听主题切换x
const { isDark, locale } = usePreferences();
watch(isDark, (dark) => {
  const theme = dark ? 'dark' : 'light';
  vditorInstance.value?.setTheme(dark ? 'dark' : 'classic', theme, theme);
});
 
// 双向绑定
const content = defineModel('value', {
  type: String,
  default: '',
});
/**
 * 为了保持外部直接(v-model)与编辑器内部的同步
 * 注意: 下面的input事件也会触发watch
 */
watch(content, (value) => {
  vditorInstance.value?.setValue(value);
});
 
// 监听禁用
function changeDisabled(disabled: boolean) {
  if (disabled) {
    vditorInstance.value?.disabled();
  } else {
    vditorInstance.value?.enable();
  }
}
watch(() => props.disabled, changeDisabled);
 
onMounted(() => {
  vditorInstance.value = new Vditor(vditorRef.value!, {
    mode: props.mode,
    value: content.value,
    height: props.height,
    lang: locale.value.replace('-', '_') as any,
    cache: {
      enable: props.enableCache,
      id: props.id,
    },
    theme: isDark.value ? 'dark' : 'classic',
    // 手动响应式
    input(value) {
      content.value = value;
    },
    // 加载完成的事件
    after() {
      // 需要初始化就禁用的情况
      changeDisabled(props.disabled);
      emit('mounted');
    },
    ...props.options,
  });
});
 
onBeforeUnmount(() => {
  vditorInstance.value?.destroy();
  vditorInstance.value = null;
});
</script>
 
<template>
  <div ref="vditorRef"></div>
</template>