code-mirror.vue 1.51 KB
<script setup lang="ts">
import { computed, nextTick, ref, useTemplateRef, watch } from 'vue';
import CodeMirror from 'vue-codemirror6';

import { usePreferences } from '@vben/preferences';

import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';

import { type LanguageSupport, languageSupportMap } from './data';

const props = withDefaults(
  defineProps<{
    /**
     * 语言
     */
    language: LanguageSupport;
    /**
     * 只读
     */
    readonly?: boolean;
  }>(),
  {
    language: 'js',
    readonly: false,
  },
);

const codeMirrorRef =
  useTemplateRef<InstanceType<typeof CodeMirror>>('codeMirrorRef');

const { isDark } = usePreferences();

const modelValue = defineModel({ default: '', type: String });

const lang = computed(() => languageSupportMap[props.language] ?? javascript());

// 通过v-if 卸载挂载达到更新语言的目的
const langChanged = ref(true);
watch(
  () => props.language,
  () => {
    langChanged.value = false;
    nextTick(() => (langChanged.value = true));
  },
);
/** 插件 */
const extensions = [oneDark];
</script>

<template>
  <CodeMirror
    v-if="langChanged"
    v-bind="$attrs"
    ref="codeMirrorRef"
    v-model="modelValue"
    :dark="isDark"
    :extensions="extensions"
    :lang="lang"
    :readonly="props.readonly"
    basic
    wrap
  >
    <template v-for="slotName in Object.keys($slots)" #[slotName]="scope">
      <slot :name="slotName" v-bind="scope ?? {}"></slot>
    </template>
  </CodeMirror>
</template>