From f40e3ed7d117d0cdbd0f006d96c23e781095c8db Mon Sep 17 00:00:00 2001 From: khj0414 Date: Fri, 7 Feb 2025 14:45:17 +0900 Subject: [PATCH] =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/editor/QEditor.vue | 51 ++++++++++++++++++---------- src/components/user/UserList.vue | 4 ++- src/components/wordDict/DictCard.vue | 10 +++--- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/components/editor/QEditor.vue b/src/components/editor/QEditor.vue index 321f170..84fee83 100644 --- a/src/components/editor/QEditor.vue +++ b/src/components/editor/QEditor.vue @@ -48,7 +48,7 @@
-
내용을 확인해주세요.
+
내용을 확인해주세요.
@@ -57,25 +57,32 @@ import Quill from 'quill'; import 'quill/dist/quill.snow.css'; import { onMounted, ref, watch, defineEmits, defineProps } from 'vue'; import $api from '@api'; + + const props = defineProps({ isAlert: { type: Boolean, default: false, }, }); -const editor = ref(null); -const font = ref('nanum-gothic'); -const fontSize = ref('16px'); + +const editor = ref(null); // 에디터 DOM 참조 +const font = ref('nanum-gothic'); // 기본 폰트 +const fontSize = ref('16px'); // 기본 폰트 크기 const emit = defineEmits(['update:data']); + onMounted(() => { + // 툴바에서 선택할 수 있는 폰트 목록 설정 const Font = Quill.import('formats/font'); Font.whitelist = ['nanum-gothic', 'd2coding', 'consolas', 'serif', 'monospace']; Quill.register(Font, true); + // 툴바에서 선택할 수 있는 폰트 크기 목록 설정 const Size = Quill.import('attributors/style/size'); Size.whitelist = ['12px', '14px', '16px', '18px', '24px', '32px', '48px']; Quill.register(Size, true); + // Quill 에디터 인스턴스 생성 const quillInstance = new Quill(editor.value, { theme: 'snow', placeholder: '내용을 입력해주세요...', @@ -86,74 +93,84 @@ onMounted(() => { syntax: true, }, }); + + // 폰트와 폰트 크기 설정 quillInstance.format('font', font.value); quillInstance.format('size', fontSize.value); + // 텍스트가 변경될 때마다 부모 컴포넌트로 변경된 내용 전달 quillInstance.on('text-change', () => { - const delta = quillInstance.getContents(); // Get Delta format + const delta = quillInstance.getContents(); // Delta 포맷으로 내용 가져오기 emit('update:data', delta); }); + // 폰트나 폰트 크기가 변경될 때 에디터 스타일 업데이트 watch([font, fontSize], () => { quillInstance.format('font', font.value); quillInstance.format('size', fontSize.value); }); - // Handle image upload - let imageUrls = new Set(); + // 이미지 업로드 기능 처리 + let imageUrls = new Set(); // 업로드된 이미지 URL을 추적 quillInstance.getModule('toolbar').addHandler('image', () => { - selectLocalImage(); + selectLocalImage(); // 이미지 버튼 클릭 시 로컬 이미지 선택 }); + + // 에디터의 텍스트가 변경될 때마다 이미지 처리 quillInstance.on('text-change', (delta, oldDelta, source) => { - // Emit Delta when content changes emit('update:data', quillInstance.getContents()); delta.ops.forEach(op => { if (op.insert && typeof op.insert === 'object' && op.insert.image) { - const imageUrl = op.insert.image; - imageUrls.add(imageUrl); + const imageUrl = op.insert.image; // 이미지 URL 추출 + imageUrls.add(imageUrl); // URL 추가 } else if (op.delete) { - checkForDeletedImages(); + checkForDeletedImages(); // 삭제된 이미지 확인 } }); }); + // 로컬 이미지 파일 선택 async function selectLocalImage() { const input = document.createElement('input'); input.setAttribute('type', 'file'); input.setAttribute('accept', 'image/*'); - input.click(); + input.click(); // 파일 선택 다이얼로그 열기 input.onchange = () => { const file = input.files[0]; if (file) { const formData = new FormData(); formData.append('file', file); + // 이미지 서버에 업로드 후 URL 받기 uploadImageToServer(formData).then(serverImageUrl => { const baseUrl = $api.defaults.baseURL.replace(/api\/$/, ''); const fullImageUrl = `${baseUrl}${serverImageUrl.replace(/\\/g, '/')}`; const range = quillInstance.getSelection(); - quillInstance.insertEmbed(range.index, 'image', fullImageUrl); + quillInstance.insertEmbed(range.index, 'image', fullImageUrl); // 선택된 위치에 이미지 삽입 - imageUrls.add(fullImageUrl); + imageUrls.add(fullImageUrl); // 이미지 URL 추가 }).catch(e => { toastStore.onToast('잠시후 다시 시도해주세요.', 'e'); }); } }; } + // 이미지 서버 업로드 async function uploadImageToServer(formData) { try { const response = await $api.post('quilleditor/upload', formData, { isFormData: true }); const imageUrl = response.data.data; - return imageUrl; + return imageUrl; // 서버에서 받은 이미지 URL 반환 } catch (error) { toastStore.onToast('잠시후 다시 시도해주세요.', 'e'); throw error; } } + + // 삭제된 이미지 확인 function checkForDeletedImages() { const editorImages = document.querySelectorAll('#editor img'); - const currentImages = new Set(Array.from(editorImages).map(img => img.src)); + const currentImages = new Set(Array.from(editorImages).map(img => img.src)); // 현재 에디터에 있는 이미지들 imageUrls.forEach(url => { if (!currentImages.has(url)) { diff --git a/src/components/user/UserList.vue b/src/components/user/UserList.vue index 2e51510..87ec5b8 100644 --- a/src/components/user/UserList.vue +++ b/src/components/user/UserList.vue @@ -14,7 +14,7 @@ > user @@ -25,10 +25,12 @@ \ No newline at end of file +imagePath ? `${baseUrl}upload/img/profile/${imagePath}` : '/img/avatars/default-Profile.jpg'; +