ํ๋ก๊ทธ๋๋ฐ ์ธ๊ณ๋ฅผ ํ๊ตฌํฉ์๋ค.
CKEditor ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ฉํ์ฌ ๊ฒ์ํ ๊ตฌ์ฑํ๊ธฐ
CKEditor ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ์ฉํ์ฌ ๊ฒ์ํ์ ํจ๊ณผ์ ์ผ๋ก ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
HTML, CSS๋ฅผ ์ ๋ถ ํ์ฉํด์ ๊ตฌํํ๋ ค๋ฉด ์ด๋ ค์ด ๊ฒ์ํ ์์๋ฅผ ๊ฐํธํ๊ฒ ์ถ๋ ฅํ ์ ์์ต๋๋ค.
์๋๋ ๊ตฌํ ์์์ ๋๋ค.
CKEditor ๋ผ์ด๋ธ๋ฌ๋ฆฌ
1. CKEditor ๋?
CKEditor๋ ์น ๊ธฐ๋ฐ์ ํ ์คํธ ์๋ํฐ๋ก, HTML๋ก ์์ฑ๋ ๋ฌธ์๋ฅผ ํธ์งํ ์ ์์ต๋๋ค.
์ด๋ ์น์ฌ์ดํธ์ ์ฌ์ฉ์๊ฐ ๋ธ๋ผ์ฐ์ ์์ ์ง์ ์ฝํ ์ธ ๋ฅผ ํธ์งํ ์ ์๊ฒ ํด์ค๋๋ค.
์ด ์๋ํฐ๋ JavaScript๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ค์ํ ์น ๋ธ๋ผ์ฐ์ ์ ํธํ๋ฉ๋๋ค.
CKEditor ์ฌ์ดํธ URL
https://ckeditor.com/ckeditor-5/
CKEditor 5 | Powerful Framework with Modular Architecture
Easy to customize RichText Editor with a powerful framework, a modular architecture, and modern features like Collaborative Editing.
ckeditor.com
CKEditor ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฃผ์ ๊ธฐ๋ฅ
CKEditor๋ ํ ์คํธ ์คํ์ผ๋ง, ๊ธ๋จธ๋ฆฌ ๊ธฐํธ์ ๋ฒํธ ๋งค๊ธฐ๊ธฐ, ํ ์ฝ์ , ๋งํฌ์ ์ด๋ฏธ์ง ์ฝ์ ๋ฑ๊ณผ ๊ฐ์ ํ๋ถํ ํ ์คํธ ํธ์ง ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
๋ํ, HTML ์ฝ๋๋ฅผ ์ง์ ํธ์งํ๋ '์์ค' ๋ชจ๋๋ ์์ต๋๋ค.
์ด ์ธ์๋ CKEditor๋ ํ๋ฌ๊ทธ์ธ ์ํคํ ์ฒ๋ฅผ ํตํด ์ฌ์ฉ์๊ฐ ์ํ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐ๋ก ๊ฐ๋ฐํ๊ณ ์ ์ฉํ ์ ์์ต๋๋ค.
CKEditor ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ ๋ฐฉ๋ฒ
์ ๋ react ํ๋ก์ ํธ์์ ์ฌ์ฉํ์์ต๋๋ค.
1. ์ค์น
๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น๋ฅผ ์งํํฉ๋๋ค.
npm install --save @ckeditor/ckeditor5-react @ckeditor/ckeditor5-build-classic
documentation ์์ ๋ค๋ฅธ ์๋ํฐ์ ์ข ๋ฅ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
https://ckeditor.com/docs/ckeditor5/latest/builds/guides/overview.html
Predefined builds | CKEditor 5 documentation
Learn how to install, integrate and configure CKEditor 5 Builds and how to work with CKEditor 5 Framework, customize it, create your own plugins and custom editors, change the UI or even bring your own UI to the editor. API reference and examples included.
ckeditor.com
2. ์ฝ๋ ์์ฑ
์๋ ์ฝ๋๋ฅผ ์ ์ ํ ์์น์ ์ ๋ ฅํฉ๋๋ค.
import React, { Component } from 'react';
import { CKEditor } from '@ckeditor/ckeditor5-react';
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
<CKEditor
editor={ClassicEditor}
data="<p>Hello from CKEditor 5!</p>"
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 });
setMountainContent({
...mountainContent,
content: data
})
console.log(mountainContent);
}}
onBlur={(event, editor) => {
console.log('Blur.', editor);
}}
onFocus={(event, editor) => {
console.log('Focus.', editor);
}}
/>
</div>
์์ธํ ์ค๋ช ์ ์๋ ๊ณต์๋ฌธ์ ์ฐธ๊ณ ๋ฐ๋๋๋ค.
https://ckeditor.com/docs/ckeditor5/latest/installation/integrations/react.html
React rich text editor component | CKEditor 5 documentation
Learn how to install, integrate and configure CKEditor 5 Builds and how to work with CKEditor 5 Framework, customize it, create your own plugins and custom editors, change the UI or even bring your own UI to the editor. API reference and examples included.
ckeditor.com
3. ์ต์ ๋์ด CSS ์ ์ฉ
์ ํ๋ก์ ํธ์ ์ฌ์ฉํ ์ฝ๋์ ๋๋ค.
Board.jsx
import Nav from '../nav/Nav';
import style from './Board.module.css';
import { CKEditor } from '@ckeditor/ckeditor5-react';
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import { useState } from 'react';
function Board() {
const [mountainContent, setMountainContent] = useState({
title: '',
content: ''
})
const [viewContent, setViewContent] = useState([]);
const getValue = e => {
const { name, value } = e.target;
setMountainContent(prevContent => ({
...prevContent,
[name]: value
}));
};
return (
<>
<div className={style.homepage_nav}>
<Nav />
</div>
<div className={style.board}>
<h1>๋ฑ์ฐ ํ๊ธฐ</h1>
<div className={style.mountain_container}>
{viewContent.map(element =>
<div>
<h2>{element.title}</h2>
<div>{element.content}</div>
</div>)}
</div>
<div className={style.form_wrapper}>
<input className={style.title_input}
type='text'
placeholder='์ ๋ชฉ'
onChange={getValue}
name='title' />
<CKEditor
editor={ClassicEditor}
data="<p>Hello from CKEditor 5!</p>"
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 });
setMountainContent({
...mountainContent,
content: data
})
console.log(mountainContent);
}}
onBlur={(event, editor) => {
console.log('Blur.', editor);
}}
onFocus={(event, editor) => {
console.log('Focus.', editor);
}}
/>
</div>
<button className={style.submit_button}
onClick={() => {
setViewContent(prevContent => prevContent.concat(mountainContent));
}}
>์
๋ ฅ</button>
</div>
</>
)
}
export default Board;
Board.module.css
.board {
text-align: center;
height: 100vh;
width: 100vw;
display: flex;
flex-direction: column;
align-items: center;
padding-top: 7rem;
}
.mountain_container {
margin: 0 auto;
width: 80%;
border: 1px solid #333;
padding: 10px 0 30px 0;
border-radius: 5px;
margin-bottom: 50px;
}
.form_wrapper {
width: 60%;
margin: 0 auto;
}
.title_input {
width: 500px;
height: 40px;
margin: 10px;
}
.text_area {
width: 80%;
min-height: 500px;
}
.submit_button {
width: 200px;
height: 50px;
font-size: 20px;
padding: 20px;
border: none;
background: indianred;
border-radius: 5px;
margin-top: 40px;
vertical-align: middle;
}
์ ์ฝ๋๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ๋ฉด ์๋์ ๊ฐ์ ํํ๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค.
๊ฒ์ํ์ ๊ธฐ๋ณธ ์์ญ์ด ๋๋ฌด ์์ต๋๋ค.
Board.css ๋ฑ ๋ฐฉ์์ ์ฌ์ฉํ ๊ฒฝ์ฐ๋ผ๋ฉด css ํ์ผ์ ์๋ ์ฝ๋๋ฅผ ์ ๋ ฅํ๋ฉด ์ต์ ๋์ด๊ฐ ์ค์ ๋ฉ๋๋ค.
.ck-editor__editable {
min-height: 30rem;
}
๊ทธ๋ฌ๋ ์ ๋ module.css ํ์์ ์ฌ์ฉํ์๊ธฐ ๋๋ฌธ์ CSS๊ฐ ์ ์ฉ๋์ง ์๋ ๋ฌธ์ ๊ฐ ์๊ฒผ์ต๋๋ค.
๊ทธ๋์ board.module.css ํ์ผ์ด ์๋ index.css์ ๊ฐ์ ๊ธ๋ก๋ฒ ์คํ์ผ์ํธ ํ์ผ์ ์ ์ฝ๋๋ฅผ ์ ๋ ฅํ์ฌ ์ต์ ๋์ด๋ฅผ ์ค์ ํ๋ ๋ฐฉ์์ผ๋ก ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์์ต๋๋ค.
index.css
/* ๊ธ๋ก๋ฒ ์คํ์ผ์ํธ ํ์ผ์ ์ถ๊ฐ */
.ck-editor__editable {
min-height: 30rem;
}
๊ตฌํ ํ๋ฉด