Files
sb-front/src/components/editor/MarkdownEditor.vue
T

69 lines
2.2 KiB
Vue
Raw Normal View History

<script setup>
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
import Editor from '@toast-ui/editor'
import '@toast-ui/editor/dist/toastui-editor.css'
import codeSyntaxHighlight from '@toast-ui/editor-plugin-code-syntax-highlight/dist/toastui-editor-plugin-code-syntax-highlight-all'
import 'prismjs/themes/prism-tomorrow.css'
import '@toast-ui/editor-plugin-code-syntax-highlight/dist/toastui-editor-plugin-code-syntax-highlight.css'
const props = defineProps({
modelValue: { type: String, default: '' },
height: { type: String, default: '400px' },
placeholder: { type: String, default: '' },
initialEditType: { type: String, default: 'wysiwyg' }, // 'markdown' | 'wysiwyg'
})
const emit = defineEmits(['update:modelValue'])
// PC(Electron)는 위지윅(contenteditable)에서 한글 IME 첫 자음이 중복되는 Chromium 버그가 있어
// 마크다운(텍스트 기반) 모드로 입력받는다. 웹/모바일(APK)은 위지윅 유지.
const isElectron = typeof navigator !== 'undefined' && /electron/i.test(navigator.userAgent)
const editType = isElectron ? 'markdown' : props.initialEditType
const el = ref(null)
let editor = null
// 에디터가 마지막으로 emit 한 값. 부모가 되돌려준 echo 를 구분해 입력 중 setMarkdown 으로 끊기지 않게.
let lastEmitted = props.modelValue || ''
onMounted(() => {
editor = new Editor({
el: el.value,
height: props.height,
initialEditType: editType,
hideModeSwitch: true,
plugins: [codeSyntaxHighlight], // 코드 구문 강조
initialValue: props.modelValue || '',
placeholder: props.placeholder,
usageStatistics: false,
autofocus: false,
events: {
change: () => {
lastEmitted = editor.getMarkdown()
emit('update:modelValue', lastEmitted)
},
},
})
})
// 외부 값 변경(수정 로드, 제출 후 초기화 등)만 에디터에 반영. echo 는 무시.
watch(
() => props.modelValue,
(val) => {
const v = val || ''
if (v === lastEmitted) return
if (editor && v !== editor.getMarkdown()) {
lastEmitted = v
editor.setMarkdown(v)
}
},
)
onBeforeUnmount(() => {
editor?.destroy()
editor = null
})
</script>
<template>
<div ref="el"></div>
</template>