change code editor to codemirror.
This commit is contained in:
55
src/shared/CodeEditor.vue
Normal file
55
src/shared/CodeEditor.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<script lang="ts" setup>
|
||||
import { Codemirror } from "vue-codemirror"
|
||||
import { cpp } from "@codemirror/lang-cpp"
|
||||
import { python } from "@codemirror/lang-python"
|
||||
import { java } from "@codemirror/lang-java"
|
||||
import { javascript } from "@codemirror/lang-javascript"
|
||||
import { LANGUAGE } from "~/utils/types"
|
||||
import { EditorView } from "@codemirror/view"
|
||||
|
||||
const styleTheme = EditorView.baseTheme({
|
||||
"&.cm-editor.cm-focused": {
|
||||
outline: "none",
|
||||
},
|
||||
})
|
||||
|
||||
interface Props {
|
||||
value: string
|
||||
language?: LANGUAGE
|
||||
fontSize?: number
|
||||
height?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
language: "C",
|
||||
fontSize: 20,
|
||||
height: "100%",
|
||||
})
|
||||
|
||||
const code = ref(props.value)
|
||||
const emit = defineEmits(["update:value"])
|
||||
|
||||
const lang = computed(() => {
|
||||
if (props.language === "C" || props.language === "C++") return cpp()
|
||||
if (props.language === "Java") return java()
|
||||
if (props.language === "JavaScript") return javascript()
|
||||
return python()
|
||||
})
|
||||
|
||||
function onChange(v: string) {
|
||||
emit("update:value", v)
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Codemirror
|
||||
v-model="code"
|
||||
:extensions="[styleTheme, lang]"
|
||||
indentWithTab
|
||||
:tabSize="4"
|
||||
@change="onChange"
|
||||
:style="{
|
||||
height: props.height,
|
||||
fontSize: props.fontSize + 'px',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
@@ -35,7 +35,6 @@ onMounted(() => {
|
||||
|
||||
const menus = computed<MenuOption[]>(() => [
|
||||
{
|
||||
show: false,
|
||||
label: () =>
|
||||
h(RouterLink, { to: "/learn/step-1" }, { default: () => "自学" }),
|
||||
key: "learn",
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import type * as Monaco from "monaco-editor"
|
||||
import { LANGUAGE_FORMAT_VALUE } from "utils/constants"
|
||||
import { LANGUAGE } from "utils/types"
|
||||
import { isMobile } from "~/shared/composables/breakpoints"
|
||||
import { isDark } from "./composables/dark"
|
||||
import { init, monaco } from "./composables/monaco"
|
||||
|
||||
interface Props {
|
||||
value: string
|
||||
language?: LANGUAGE
|
||||
height?: string
|
||||
fontSize?: number
|
||||
class?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
language: "C",
|
||||
height: "calc(100vh - 92px)",
|
||||
fontSize: 20,
|
||||
class: "",
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "update:value", value: string): void
|
||||
}>()
|
||||
|
||||
const monacoEditorRef = ref()
|
||||
let editor: Monaco.editor.IStandaloneCodeEditor
|
||||
let model: Monaco.editor.ITextModel
|
||||
|
||||
onMounted(async () => {
|
||||
if (!monaco.value) await init()
|
||||
model = monaco.value!.editor.createModel(
|
||||
props.value,
|
||||
LANGUAGE_FORMAT_VALUE[props.language]
|
||||
)
|
||||
|
||||
editor = monaco.value!.editor.create(monacoEditorRef.value, {
|
||||
model,
|
||||
theme: isDark.value ? "dark" : "light", // 官方自带三种主题vs, hc-black, or vs-dark
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
lineNumbersMinChars: 2,
|
||||
automaticLayout: true, // 自适应布局
|
||||
tabSize: 4,
|
||||
fontSize: props.fontSize || (isMobile.value ? 20 : 22), // 字体大小
|
||||
scrollBeyondLastLine: false,
|
||||
lineDecorationsWidth: 0,
|
||||
scrollBeyondLastColumn: 0,
|
||||
glyphMargin: false,
|
||||
scrollbar: {
|
||||
useShadows: false,
|
||||
vertical: "hidden",
|
||||
horizontal: "hidden",
|
||||
},
|
||||
overviewRulerLanes: 0,
|
||||
})
|
||||
|
||||
model.onDidChangeContent(() => {
|
||||
const value = model.getValue().toString()
|
||||
emit("update:value", value)
|
||||
})
|
||||
|
||||
editor.onKeyDown((e) => {
|
||||
if ((e.ctrlKey || e.metaKey) && e.code === "KeyS") {
|
||||
e.preventDefault()
|
||||
}
|
||||
if ((e.ctrlKey || e.metaKey) && e.code === "KeyR") {
|
||||
e.preventDefault()
|
||||
}
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
if (!monaco.value) return
|
||||
monaco.value.editor.setModelLanguage(
|
||||
model,
|
||||
LANGUAGE_FORMAT_VALUE[props.language]
|
||||
)
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
if (props.value !== model.getValue()) {
|
||||
model.setValue(props.value)
|
||||
}
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
if (!monaco.value) return
|
||||
monaco.value.editor.setTheme(isDark.value ? "dark" : "light")
|
||||
})
|
||||
})
|
||||
onUnmounted(() => {
|
||||
editor && editor.dispose()
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
v-if="monaco"
|
||||
ref="monacoEditorRef"
|
||||
:class="props.class"
|
||||
:style="{ height: props.height }"
|
||||
></div>
|
||||
<div v-else :style="{ height: props.height }"></div>
|
||||
</template>
|
||||
<style scoped></style>
|
||||
@@ -1,25 +0,0 @@
|
||||
import loader, { Monaco } from "@monaco-editor/loader"
|
||||
import * as monaco0301 from "monaco-editor"
|
||||
import { isLowVersion } from "~/utils/functions"
|
||||
|
||||
export const monaco = ref<Monaco>()
|
||||
|
||||
export async function init() {
|
||||
if (isLowVersion) {
|
||||
loader.config({ monaco: monaco0301 })
|
||||
} else {
|
||||
loader.config({
|
||||
paths: { vs: "https://cdn.staticfile.org/monaco-editor/0.36.1/min/vs" },
|
||||
"vs/nls": { availableLanguages: { "*": "zh-cn" } },
|
||||
})
|
||||
}
|
||||
|
||||
const [m, light, dark] = await Promise.all([
|
||||
loader.init(),
|
||||
fetch("/light.json").then((t) => t.json()),
|
||||
fetch("/dark.json").then((t) => t.json()),
|
||||
])
|
||||
monaco.value = m
|
||||
monaco.value.editor.defineTheme("light", light)
|
||||
monaco.value.editor.defineTheme("dark", dark)
|
||||
}
|
||||
Reference in New Issue
Block a user