11<template >
2- <div class =" flex bg-white h-full relative overflow-hidden" >
3- <!-- 行号 -->
4- <div ref =" lineNumbersRef"
5- class =" bg-gray-50 text-gray-400 text-sm font-mono px-3 pb-4 select-none border-r border-gray-200 overflow-hidden flex-shrink-0 z-10"
6- style =" padding-top : 0 ;" >
7- <div v-for =" (num, index) in lineNumbers" :key =" index" class =" h-6 leading-6 text-right" >
8- {{ num }}
9- </div >
10- </div >
11-
12- <!-- 语法高亮容器 -->
13- <div class =" flex-1 relative overflow-hidden" >
14- <!-- 高亮显示层 -->
15- <pre ref =" highlightRef"
16- class =" absolute inset-0 px-4 pb-4 font-mono text-sm leading-6 bg-transparent pointer-events-none overflow-auto whitespace-pre-wrap z-0"
17- style =" margin : 0 ; border : 0 ; padding-top : 0 ; word-break : break-word ; white-space : pre-wrap ;"
18- v-html =" highlightedCode" ></pre >
19-
20- <!-- 代码输入框 -->
21- <textarea ref =" textareaRef"
22- :value =" modelValue"
23- @input =" handleInput"
24- @keydown =" handleKeyDown"
25- @scroll =" handleScroll"
26- class =" absolute inset-0 px-4 pb-4 font-mono text-sm leading-6 resize-none outline-none bg-transparent z-10 overflow-auto"
27- style =" color : transparent ; caret-color : #374151 ; margin : 0 ; border : 0 ; padding-top : 0 ; word-break : break-word ; white-space : pre-wrap ;"
28- placeholder =" 在此输入代码..."
29- spellcheck =" false" >
30- </textarea >
31- </div >
2+ <div class =" flex bg-white h-full relative" >
3+ <Codemirror v-if =" isReady"
4+ style =" width : 100% ; height : 100% "
5+ :model-value =" modelValue"
6+ :extensions =" extensions"
7+ :indent-with-tab =" editorConfig?.indent_with_tab"
8+ :tab-size =" editorConfig?.tab_size"
9+ @change =" handleInput" />
3210 </div >
3311</template >
3412
3513<script setup lang="ts">
36- import { computed , nextTick , ref } from ' vue'
37- import { highlightCode } from ' ../utils/highlighter'
14+ import { onMounted } from ' vue'
15+ import { Codemirror } from ' vue-codemirror'
16+ import { useCodeMirrorEditor } from ' ../composables/useCodeMirrorEditor'
3817
3918const props = defineProps <{
4019 modelValue: string
@@ -45,46 +24,18 @@ const emit = defineEmits<{
4524 ' update:modelValue' : [value : string ]
4625}>()
4726
48- const textareaRef = ref <HTMLTextAreaElement >()
49- const lineNumbersRef = ref <HTMLElement >()
50- const highlightRef = ref <HTMLPreElement >()
51-
52- const lineNumbers = computed (() => {
53- const lines = props .modelValue .split (' \n ' )
54- return lines .map ((_ , index ) => String (index + 1 ))
55- })
56-
57- const highlightedCode = computed (() => {
58- return highlightCode (props .modelValue , props .language || ' python3' )
59- })
27+ const {
28+ isReady,
29+ extensions,
30+ editorConfig,
31+ initializeEditor
32+ } = useCodeMirrorEditor (props , emit )
6033
61- const handleInput = (e : Event ) => {
62- const target = e .target as HTMLTextAreaElement
63- emit (' update:modelValue' , target .value )
34+ const handleInput = (value : string ) => {
35+ emit (' update:modelValue' , value )
6436}
6537
66- const handleKeyDown = async (e : KeyboardEvent ) => {
67- if (e .key === ' Tab' ) {
68- e .preventDefault ()
69- const target = e .target as HTMLTextAreaElement
70- const start = target .selectionStart
71- const end = target .selectionEnd
72- const newValue = props .modelValue .substring (0 , start ) + ' ' + props .modelValue .substring (end )
73- emit (' update:modelValue' , newValue )
74-
75- await nextTick ()
76- target .selectionStart = target .selectionEnd = start + 4
77- }
78- }
79-
80- const handleScroll = (e : Event ) => {
81- const target = e .target as HTMLTextAreaElement
82- if (lineNumbersRef .value ) {
83- lineNumbersRef .value .scrollTop = target .scrollTop
84- }
85- if (highlightRef .value ) {
86- highlightRef .value .scrollTop = target .scrollTop
87- highlightRef .value .scrollLeft = target .scrollLeft
88- }
89- }
90- </script >
38+ onMounted (async () => {
39+ await initializeEditor ()
40+ })
41+ </script >
0 commit comments