2024. 1. 15. 16:09ㆍ뷰(Vue)
Vue3를 기반으로하는 프로젝트에서 에디터 적용이 필요하여 여러가지 대조군을 비교하며 정리하였다.
최초에 대상이 되던 플러그인은 총 3가지로 다음과 같았다.
- Sun Editor —> 이미지 resize 선택하여 가능 (Vue지원)
- Tiptap Editor
- Ckeditor5 ckeditor5-Vue 지원. 그러나 이전 js버전의 경우 image resize가 정상적으로 동작안한다고 함. 확인이 필요하다.
위와 같은 리스트업중 필요성과 접근성 등등 여러가지를 고려해서 확인 해보았다.
sun editor를 사용할까 했었는데.. Vue를 지원하는것 같지만 들어가보면 소스가 없다. (텅 비어있음.)
Tiptap과 ckeditor5는 모두 image resize를 제공하는듯 보였다.
사람들이 이미 익숙하게 사용중인 ckeditor5를 적용해보자.
주소
https://github.com/ckeditor/ckeditor5-vue
원하는 컴포넌트를 골라서 설치하라고 한다.
리스트
위 리스트에서 원하는 형태로도 제공하고 데모버전도 확인 할 수 있는 사이트가 별도로 있었다. 유명하면서도 여러가지 참고 할 수 있는 자료가 다른 플러그인들에 비해서 확실히 많았다.
설치 명령어
npm install @ckeditor/ckeditor5-vue @ckeditor/ckeditor5-build-classic
main.js 글로벌 설정 추가
import { createApp } from 'vue';
import CKEditor from '@ckeditor/ckeditor5-vue';
createApp( { /* options */ } ).use( CKEditor ).mount( /* DOM element */ );
Vue3 에서 적용한 예시들 공식문서
Vue.js 3+ rich text editor component | CKEditor 5 documentation
만약 builder를 통한 예시파일을 받아서 확인해보고 싶다면..!
원하는 옵션들을 추가한 builder를 제공한다. 예시화면을 보고싶다면 참고하면 좋을듯 하다.
CKEditor 5 Online Builder | Create your own editor in 5 steps
해당사이트에 들어가면 다음과 같이 모드 선택도 가능하고
그다음 스텝에선 원하는 모듈을 선택하여 선택한 모듈을 포함한 파일을 확인 할 수 있다.
결국 최종적으로는 다음과 같은 형태로 적용하였다.
추가 플러그인들 설치
npm install @ckeditor/ckeditor5-editor-classic
npm install @ckeditor/ckeditor5-essentials
npm install @ckeditor/ckeditor5-basic-styles
npm install @ckeditor/ckeditor5-link
npm install @ckeditor/ckeditor5-paragraph
npm install @ckeditor/ckeditor5-indent
npm install @ckeditor/ckeditor5-list
npm install @ckeditor/ckeditor5-table
npm install @ckeditor/ckeditor5-typing
npm install @ckeditor/ckeditor5-alignment
npm install @ckeditor/ckeditor5-autoformat
npm install @ckeditor/ckeditor5-image
npm install @ckeditor/ckeditor5-vue
npm install @ckeditor/ckeditor5-media-embed
npm install @ckeditor/ckeditor5-theme-lark
vite.config.js
vite를 사용하기 때문에 다음과 같이 설정 추가
import { fileURLToPath, URL } from 'node:url';
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { manualChunksPlugin } from 'vite-plugin-webpackchunkname';
// ckeditor
import ckeditor5 from '@ckeditor/vite-plugin-ckeditor5';
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
export default defineConfig({
plugins: [vue(), manualChunksPlugin(), ckeditor5({ theme: require.resolve('@ckeditor/ckeditor5-theme-lark') })],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
});
CommonCkeditor.vue 파일
<template>
<Ckeditor :editor="editor" v-model="text" :config="editorConfig"></Ckeditor>
</template>
<script setup>
import { ClassicEditor } from '@ckeditor/ckeditor5-editor-classic';
import { Essentials } from '@ckeditor/ckeditor5-essentials';
import { Bold, Italic } from '@ckeditor/ckeditor5-basic-styles';
import { BlockQuote } from '@ckeditor/ckeditor5-block-quote';
import { Link } from '@ckeditor/ckeditor5-link';
import { Paragraph } from '@ckeditor/ckeditor5-paragraph';
import { Indent } from '@ckeditor/ckeditor5-indent';
import { List } from '@ckeditor/ckeditor5-list';
import { MediaEmbed } from '@ckeditor/ckeditor5-media-embed';
import { Table, TableColumnResize, TableToolbar } from '@ckeditor/ckeditor5-table';
import { TextTransformation } from '@ckeditor/ckeditor5-typing';
import { Alignment } from '@ckeditor/ckeditor5-alignment';
import { Image, ImageCaption, ImageStyle, ImageToolbar, ImageUpload, ImageResize } from '@ckeditor/ckeditor5-image';
import { ref, watch } from 'vue';
let text = ref();
const emits = defineEmits(['update:modelValue']);
/**
* v-model 값 연결
*/
watch(text, (newValue, oldValue) => {
emits('update:modelValue', newValue);
});
// import Upload Adapter
import UploadAdapter from '@/components/common/editor/UploadAdapter';
// Custom Upload Adapter Plugin function
function CustomUploadAdapterPlugin(editor) {
editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
// Create new object and pass server url
return new UploadAdapter(loader, '');
};
}
const editor = ClassicEditor;
const editorConfig = {
extraPlugins: [CustomUploadAdapterPlugin],
plugins: [
Essentials,
Bold,
Italic,
Link,
Paragraph,
BlockQuote,
Indent,
List,
Table,
TableToolbar,
TableColumnResize,
TextTransformation,
Alignment,
Image,
ImageCaption,
ImageStyle,
ImageToolbar,
ImageUpload,
ImageResize,
MediaEmbed,
],
toolbar: {
items: [
'bold',
'italic',
'link',
'imageUpload',
'indent',
'outdent',
'numberedList',
'bulletedList',
'alignment',
'blockQuote',
'mediaEmbed',
'undo',
'redo',
'insertTable',
],
},
image: {
toolbar: [
'imageTextAlternative',
'toggleImageCaption',
'imageStyle:inline',
'imageStyle:block',
'imageStyle:side',
],
},
table: {
contentToolbar: ['tableColumn', 'tableRow', 'mergeTableCells', 'tableProperties', 'tableCellProperties'],
},
};
</script>
<style>
.ck.ck-editor {
width: 100%;
margin: 0 auto;
}
.ck-editor__editable {
min-height: 200px !important;
max-height: 400px !important;
}
</style>
파일업로드 로직 커스텀을 위한 파일추가.
UploadAdapter.js
import axios from '@/api/defaultAxios';
const noConextPathUrl = import.meta.env.VITE_APP_NO_CONTEXT_PATH_URL;
export default class UploadAdapter {
constructor(loader, url) {
this.url = url;
this.loader = loader;
this.loader.file.then((pic) => (this.file = pic));
this.upload();
}
// Starts the upload process.
upload() {
return this.loader.file.then((uploadedFile) => {
return new Promise((resolve, reject) => {
const params = {
upload: uploadedFile,
};
axios.api
.fetchFileUpload(params)
.then((res) => {
const returnUrl = res.data.data.url;
resolve({
default: `${noConextPathUrl}${returnUrl}`,
});
})
.catch((error) => {
console.log(error);
reject(error.response.data.message);
});
});
});
}
}
보고 참고한 인터넷 글
https://favourkelvin17.medium.com/using-ckeditor-5-with-vue-js-a-step-by-step-guide-ff231bf226ed
이미지 업로드 로직 구성하는데 실질적으로 참고한 사이트
stackoverflow 답변 중 참고.
https://stackoverflow.com/questions/55105674/ckeditor-upload-adapter-sends-object-promise-to-server
적용된 예시 모습
다른사람이 만들어둔 오픈소스를 사용하는데도 여기저기 참고해야 하는 부분들이 많아서 개인적으로 따로 정리를 하였다
그래도 한번 작업해두면 두고두고 쓸 수 있으니 만들어준 사람들에게 항상 감사함을 표한다.
'뷰(Vue)' 카테고리의 다른 글
Vue3 Validation 플러그인 적용하기(VeeValidate + yup + i18n)_1 (0) | 2024.01.15 |
---|---|
Vue3에서 i18n(다국어) 적용하기..! (0) | 2024.01.15 |
axios요청 후 커스텀 header값 못 읽는 문제해결 방법(JWT) (0) | 2024.01.12 |
Vue3 프로젝트에 PrimeVue 적용하기.(Bootstrap-vue, Bootstrap-vue-3 ,Bootstrap-vue-next 대체) (0) | 2024.01.12 |
Vue에 캘린더 달력(Vue Date Picker) 공통 컴퍼넌트화 해서 적용하기. (1) | 2024.01.11 |