Search

WYSIWYG 에디터 - CKEditor

WYSIWYG 에디터 - CKEditor

β€’
μœ„μ§€μœ… μ—λ””ν„°λž€?
β€’
React 에 CKEditor μ„€μΉ˜
β€’
μƒ˜ν”Œμ½”λ“œ
β—¦
import
β—¦
μ»΄ν¬λ„ŒνŠΈ

μœ„μ§€μœ… μ—λ””ν„°λž€?

WYSIWYG (What You See Is What You Get) : μž‘μ„±ν•˜λŠ” λ‚΄μš©μ„ κ·ΈλŒ€λ‘œ λ³΄λ©΄μ„œ νŽΈμ§‘ν•  수 μžˆλŠ” 에디터
μœ„μ§€μœ…(What You See Is What You Get) μ—λ””ν„°λŠ” μ‚¬μš©μžκ°€ 결과물을 λ³΄λ©΄μ„œ μ½˜ν…μΈ λ₯Ό νŽΈμ§‘ν•  수 μžˆλŠ” λ„κ΅¬μž…λ‹ˆλ‹€. μ‚¬μš©μžλŠ” ν…μŠ€νŠΈ ν˜•μ‹, 이미지, ν‘œ 등을 직접 μ‘°μž‘ν•˜μ—¬ μ›Ή μ½˜ν…μΈ λ₯Ό λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ μ—λ””ν„°λŠ” μ‚¬μš©μžκ°€ HTMLμ΄λ‚˜ CSS 같은 λ§ˆν¬μ—… μ–Έμ–΄λ₯Ό λͺ°λΌλ„ μ›Ή μ½˜ν…μΈ λ₯Ό μ‰½κ²Œ λ§Œλ“€ 수 있게 ν•΄μ€λ‹ˆλ‹€.
μ›Ήμ—μ„œλŠ” HTML ν˜•μ‹μœΌλ‘œ 컨텐츠가 λ³΄μ—¬μ§€λŠ”λ°, 일반 ν…μŠ€νŠΈλ₯Ό μž‘μ„±ν•˜λ©΄, 제λͺ©, 문단, 이미지 등을 κ·ΈλŒ€λ‘œ λ³Ό μˆ˜κ°€ μ—†λ‹€. 그런데 μœ„μ§€μœ… 에디터λ₯Ό μ΄μš©ν•˜λ©΄, μž‘μ„±ν•˜λŠ” 컨텐츠λ₯Ό κ·ΈλŒ€λ‘œ HTML 둜 λ³€ν™˜ν•˜μ—¬ 보여주기 λ•Œλ¬Έμ—, μžˆλŠ” κ·ΈλŒ€λ‘œ μž‘μ„±ν•˜λ©΄μ„œ λ³Ό 수 μžˆλ‹€.

React 에 CKEditor μ„€μΉ˜

npm install --save @ckeditor/ckeditor5-react @ckeditor/ckeditor5-build-classic
Bash
볡사
npm install --save @ckeditor/ckeditor5-alignment
Bash
볡사

μƒ˜ν”Œμ½”λ“œ

import

// ckeditor5 import { CKEditor } from '@ckeditor/ckeditor5-react'; import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
JavaScript
볡사

μ»΄ν¬λ„ŒνŠΈ

<CKEditor editor={ ClassicEditor } config={{ placeholder: "λ‚΄μš©μ„ μž…λ ₯ν•˜μ„Έμš”.", toolbar: { items: [ 'undo', 'redo', '|', 'heading', '|', 'fontfamily', 'fontsize', 'fontColor', 'fontBackgroundColor', '|', 'bold', 'italic', 'strikethrough', 'subscript', 'superscript', 'code', '|', 'bulletedList', 'numberedList', 'todoList', 'outdent', 'indent', '|', 'link', 'uploadImage', 'blockQuote', 'codeBlock', '|', 'mediaEmbed', ], shouldNotGroupWhenFull: false }, editorConfig: { height: 500, // Set the desired height in pixels }, alignment: { options: ['left', 'center', 'right', 'justify'], }, // extraPlugins: [uploadPlugin] // μ—…λ‘œλ“œ ν”ŒλŸ¬κ·ΈμΈ }} data="" // ⭐ κΈ°μ‘΄ 컨텐츠 λ‚΄μš© μž…λ ₯ (HTML) onReady={ editor => { // You can store the "editor" and use when it is needed. console.log( 'Editor is ready to use!', editor ); } } onChange={ ( event, editor ) => { const data = editor.getData(); console.log( { event, editor, data } ); setContent(data); } } onBlur={ ( event, editor ) => { console.log( 'Blur.', editor ); } } onFocus={ ( event, editor ) => { console.log( 'Focus.', editor ); } } />
JavaScript
볡사

에디터 μ‚¬μš©

β€’
κ²Œμ‹œκΈ€ 등둝
β€’
κ²Œμ‹œκΈ€ μˆ˜μ •
β€’
κ²Œμ‹œκΈ€ 쑰회

κ²Œμ‹œκΈ€ 등둝

<CKEditor editor={ ClassicEditor } config={{ placeholder: "λ‚΄μš©μ„ μž…λ ₯ν•˜μ„Έμš”.", toolbar: { items: [ 'undo', 'redo', '|', 'heading', '|', 'fontfamily', 'fontsize', 'fontColor', 'fontBackgroundColor', '|', 'bold', 'italic', 'strikethrough', 'subscript', 'superscript', 'code', '|', 'bulletedList', 'numberedList', 'todoList', 'outdent', 'indent', '|', 'link', 'uploadImage', 'blockQuote', 'codeBlock', '|', 'mediaEmbed', ], shouldNotGroupWhenFull: false }, editorConfig: { height: 500, // Set the desired height in pixels }, alignment: { options: ['left', 'center', 'right', 'justify'], }, // extraPlugins: [uploadPlugin] // μ—…λ‘œλ“œ ν”ŒλŸ¬κ·ΈμΈ }} data="" // ⭐ κΈ°μ‘΄ 컨텐츠 λ‚΄μš© μž…λ ₯ (HTML) onReady={ editor => { // You can store the "editor" and use when it is needed. console.log( 'Editor is ready to use!', editor ); } } onChange={ ( event, editor ) => { const data = editor.getData(); console.log( { event, editor, data } ); setContent(data); } } onBlur={ ( event, editor ) => { console.log( 'Blur.', editor ); } } onFocus={ ( event, editor ) => { console.log( 'Focus.', editor ); } } />
JavaScript
볡사

κ²Œμ‹œκΈ€ μˆ˜μ •

<CKEditor editor={ ClassicEditor } config={{ placeholder: "λ‚΄μš©μ„ μž…λ ₯ν•˜μ„Έμš”.", toolbar: { items: [ 'undo', 'redo', '|', 'heading', '|', 'fontfamily', 'fontsize', 'fontColor', 'fontBackgroundColor', '|', 'bold', 'italic', 'strikethrough', 'subscript', 'superscript', 'code', '|', 'bulletedList', 'numberedList', 'todoList', 'outdent', 'indent', '|', 'link', 'uploadImage', 'blockQuote', 'codeBlock', '|', 'mediaEmbed', ], shouldNotGroupWhenFull: false }, editorConfig: { height: 500, // Set the desired height in pixels }, alignment: { options: ['left', 'center', 'right', 'justify'], }, // extraPlugins: [uploadPlugin] // μ—…λ‘œλ“œ ν”ŒλŸ¬κ·ΈμΈ }} data={content} // ⭐ κΈ°μ‘΄ 컨텐츠 λ‚΄μš© μž…λ ₯ (HTML) onReady={ editor => { // You can store the "editor" and use when it is needed. console.log( 'Editor is ready to use!', editor ); } } onChange={ ( event, editor ) => { const data = editor.getData(); console.log( { event, editor, data } ); setContent(data); } } onBlur={ ( event, editor ) => { console.log( 'Blur.', editor ); } } onFocus={ ( event, editor ) => { console.log( 'Focus.', editor ); } } />
JavaScript
볡사

κ²Œμ‹œκΈ€ 쑰회

<CKEditor editor={ ClassicEditor } data={ content } // μ‘°νšŒν•  데이터 컨텐츠 disabled={true} config={{ toolbar: [], }} />
JavaScript
볡사

μ—λ””ν„°μ—μ„œ 파일 μ—…λ‘œλ“œ 적용

β€’
uploadPlugin() ν•¨μˆ˜ μ •μ˜
β€’
customUploadAdapter() ν•¨μˆ˜ μ •μ˜
β€’
extraPlugins: [uploadPlugin]

uploadPlugin() ν•¨μˆ˜ μ •μ˜

function uploadPlugin(editor) { editor.plugins.get("FileRepository").createUploadAdapter = (loader) => { return customUploadAdapter(loader); }; }
JavaScript
볡사

customUploadAdapter() ν•¨μˆ˜ μ •μ˜

const customUploadAdapter = (loader) => { return { upload() { return new Promise( (resolve, reject) => { const formData = new FormData(); loader.file.then( async (file) => { console.log(file); formData.append("parentTable", 'editor'); formData.append("file", file); const headers = { headers: { 'Content-Type' : 'multipart/form-data', }, }; let response = await files.upload(formData, headers); let data = await response.data; console.log(`data : ${data}`); let newFile = data; let newFileNo = newFile.no // 이미지 λ Œλ”λ§ await resolve({ default: `http://localhost:8080/files/img/${newFileNo}` }) }); }); }, }; };
JavaScript
볡사

extraPlugins: [uploadPlugin] μ„€μ •

extraPlugins: [uploadPlugin]
<CKEditor editor={ ClassicEditor } config={{ placeholder: "λ‚΄μš©μ„ μž…λ ₯ν•˜μ„Έμš”.", toolbar: { items: [ 'undo', 'redo', '|', 'heading', '|', 'fontfamily', 'fontsize', 'fontColor', 'fontBackgroundColor', '|', 'bold', 'italic', 'strikethrough', 'subscript', 'superscript', 'code', '|', 'bulletedList', 'numberedList', 'todoList', 'outdent', 'indent', '|', 'link', 'uploadImage', 'blockQuote', 'codeBlock', '|', 'mediaEmbed', ], shouldNotGroupWhenFull: false }, editorConfig: { height: 500, // Set the desired height in pixels }, alignment: { options: ['left', 'center', 'right', 'justify'], }, extraPlugins: [uploadPlugin] // μ—…λ‘œλ“œ ν”ŒλŸ¬κ·ΈμΈ }} data="" // ⭐ κΈ°μ‘΄ 컨텐츠 λ‚΄μš© μž…λ ₯ (HTML) onReady={ editor => { // You can store the "editor" and use when it is needed. console.log( 'Editor is ready to use!', editor ); } } onChange={ ( event, editor ) => { const data = editor.getData(); console.log( { event, editor, data } ); setContent(data); } } onBlur={ ( event, editor ) => { console.log( 'Blur.', editor ); } } onFocus={ ( event, editor ) => { console.log( 'Focus.', editor ); } } />
JavaScript
볡사