์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- webpack
- Import
- await
- https://m.blog.naver.com/tt2t2am1118/221010125300
- eport
- Porject
- db
- js
- ๋น๋๊ธฐ
- setTimeout()
- ํผํ
- prj
- sql
- object
- JS #ํ๋ก์ ํธ
- mysql
- slow and steady
- Project
- addEventListener
- ๊ฒ์
- async
- callback
- ๋๊ธฐ
- promise
- database
- ์ฐธ๊ณ ๋ธ๋ก๊ทธ
- ajax
- https://youtube.com/playlist?list=PLuHgQVnccGMA5836CvWfieEQy0T0ov6Jh&si=FTaYv8m21EhO-A2K
- json
- execCommand
- Today
- Total
C-log
[FE]๋๋ง์ ์ํ์ง์ ์๋ํฐ์ ํด๋ฐ๋ฅผ ์ง์ ์ ์ํ๋ค.(๊ธฐ๋ณธ ํด๋ฐ ์ ์) ๋ณธ๋ฌธ
[FE]๋๋ง์ ์ํ์ง์ ์๋ํฐ์ ํด๋ฐ๋ฅผ ์ง์ ์ ์ํ๋ค.(๊ธฐ๋ณธ ํด๋ฐ ์ ์)
4:Bee 2024. 3. 22. 16:06์์ ํฌ์คํ ์์ react-quill์ ์ฌ์ฉํ์ง ์๊ณ ์ง์ ์๋ํฐ์ ํด๋ฐ๋ฅผ ์ ์ํ๊ธฐ๋ก ๊ฒฐ์ ํ๋ค. ๊ทธ๋ฌ๊ธฐ ์ํด์๋ ๋๊ฐ์ง๋ฅผ ์์์ผ ํ๋ค. ์ฒซ ๋ฒ์งธ๋ก contentEditable๊ณผ execCommand์ด๋ค.
# contentEditable
contentEditable์ HTML ์์์ ์์ฑ(attribute) ์ค ํ๋๋ก, ์ฌ์ฉ์๊ฐ ํด๋น ์์์ ๋ด์ฉ์ ์ง์ ํธ์งํ ์ ์๊ฒ ํ๋ ๊ธฐ๋ฅ์ ํ์ฑํํ๋ ์ญํ ์ ํ๋ค. ๋ฐ๋ผ์ ์ํ๋ ํ๊ทธ์ contentEditable="true"๋ฅผ ๊ธฐ์ ํ๊ฒ ๋๋ฉด ์น ํ์ด์ง๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ์์ ํ ์คํธ ์ ๋ ฅ ์์๋ ํธ์ง ๊ฐ๋ฅํ ์ปจํ ์ธ ๊ฐ ๋๋ค. ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์๋์ ๊ฐ๋ค.
๋ฐ๋ผ์ divํ๊ทธ๊ฐ ํธ์ง์ ํ ์ ์๊ฒ ๋ ๊ฒ์ด๋ค. ์ฌ์ฉ์๊ฐ ์ ๋ ฅ์ ์ง์ ๊ธฐ์ ํ ์ ์๋ ์๋ํฐ๋ก ์ง์ ์ด ๋ ๊ฒ์ด๋ค. ์ฌ๊ธฐ์ dangerouslySetInnerHTML={{ __html: content }}๋ content๋ผ๋ ๋ณ์์ ๋ค์ด ์๋ HTML ๋ฌธ์์ด์ ํด๋น <div> ์์์ ๋ด๋ถ HTML๋ก ์ค์ ํ๋ ์ญํ ์ ํ๋ค. ๋ฐ๋ผ์ content์ ์๋ HTML์ด <div> ๋ด๋ถ์ ๋ ๋๋ง๋๋ค. ์ฆ, content์๋ HTML ๋ฌธ์์ด๋ก ์ ์ฅ์ด ๋์ด ์๋๋ฐ ์ด๊ฒ์ ์ผ๋ฐ ๋ฌธ์์ด๋ก ๋ ๋๋ง ํ๊ธฐ ์ํด์ dangerouslySetInnerHTML๋ก ๋ ๋๋ง์ด ๋๋ ๊ฒ์ด๋ค. ํ์ง๋ง ์ฐ๋ฆฌ๋ HTML๋ฌธ์์ด๋ก ์ ์ ์ฅ์ด๋๋์ง ์์๋ก ํ์ธํ๊ธฐ ์ํด ์๋ divํ๊ทธ๋ฅผ ์ถ๊ฐํด์ ํ์ธ ํด๋ณด๊ณ ์๋ค.
# ref={editorRef} ๊ทธ๋ฆฌ๊ณ useRef
* ref={editorRef
ref={editorRef}์ ref๋ react์์ ์ฌ์ฉ๋๋ ํน๋ณํ ์์ฑ์ผ๋ก, react ์๋ฆฌ๋จผํธ๋ ์ปดํฌ๋ํธ์ ๋ํ ์ฐธ์กฐ๋ฅผ ์์ฑํ๋ ๋ฐ ์ฌ์ฉ๋๋ค. ์ด๋ฅผ ํตํด DOM ์์์ ์ง์ ์ ์ผ๋ก ์ ๊ทผํ๊ฑฐ๋ ์กฐ์ํ ์ ์๋ค.
* useRef
useRef๋ react์์ ํจ์ํ ์ปดํฌ๋ํธ์์๋ ๊ฐ์ด ๋ณํ ์ ์๋ ์ํ๋ฅผ ์ ์งํ ์ ์๋๋ก ๋์์ฃผ๋ Hook์ด๋ค. ์ด๋ฅผ ์ฌ์ฉํ์ฌ DOM ์์์ ์ ๊ทผํ๊ฑฐ๋, ์ปดํฌ๋ํธ ๋ด๋ถ์์ ๊ฐ์ด ๋ณํ ์ ์๋ ์ํ๋ฅผ ์ ์งํ ์ ์๋ค. ์ฌ๊ธฐ์ const editorRef = useRef(null);์ ์ด๊ธฐ๊ฐ์ด null์ธ ์๋ก์ด ref๋ฅผ ์์ฑํ๋ ๊ฒ์ด๋ค. ์ด editorRef๋ <div> ์์์ ๋ํ ์ฐธ์กฐ๋ฅผ ์ ์ฅํ ์ ์๋ ๋ณ์์ด๋ค. useRef๋ฅผ ํตํด ์์ฑ๋ editorRef๋ฅผ ์ฌ์ฉํ๋ฉด ํด๋น ๋ณ์๋ฅผ ํตํด <div> ์์์ ์ง์ ์ ์ผ๋ก ์ ๊ทผํ ์ ์๋ค. ์ฆ, useRef๋ฅผ ์ฌ์ฉํจ์ผ๋ก ๋ด๊ฐ ์ํ๋ DOM ์์์ ref๋ฅผ ํตํด ์ฐธ์กฐ๋ฅผ ํด์ DOM์์์ ์ ๊ทผํ๋ ๊ฒ์ด๋ค. ์ด์ ์์ผ๋ก eidtorRef๋ฅผ ๊ณ์ ํด์ ์ฐธ์กฐํ๊ฒ ๋๋ ํจ์๋ค์ด ๋ฑ์ฅํ ๊ฒ์ด๋ค. ์ ์ฌํ ํ์ธํ ํ์๊ฐ ์๋ค.
# ํด๋ฐ๋ฅผ ์ ์ํ๋ค.
์์ ์ฐ๋ฆฌ๋ contentEditable์ ์ด์ฉํด์ ํด์ ์ฌ์ฉ ํ ์ ์๋ ํ๊ฒฝ์ ๊ตฌ์ฑํ๋ค ์ด์ ๊ฐ๊ธฐ ํ์ํ ๋ฒํผ๋ค์ ๊ตฌํ ํด๋ณด๊ฒ ๋ค.
์์ ๊ฐ์ ๋ฒํผ๋ค์ ๊ตฌํํ๊ณ ๊ฐ๊ธฐ ํจ๊ณผ๋ฅผ ์ค ์ ์๋ ํจ์๋ค์ ๊ตฌํ ํด๋ณด์๋ค.
์์ ๊ฐ์ ์ฝ๋๋ค์ ๊ตฌ์ฑ์ ๋ณด๋ฉด ๋๋ฌด ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง๋ค๊ณ ๋๊ปด์ง๋ค. ๊ทธ๋์ ์ด ์ฝ๋๋ฅผ ์กฐ๊ธ ๋ ๊ฐ์ํ ํ ์ ์์ง ์์๊น ๊ณ ๋ฏผ ํ๋ค. ๊ทธ๋์ ๋ฒํผ์ value ๊ฐ์ผ๋ก ๊ฐ๊ธฐ ์คํ์ผ ์ด๋ฆ์ผ๋ก ์ ์ํ๊ณ ์ด๋ฅผ ์ด๋ฒคํธ๋ก ์ฒ๋ฆฌํจ์ผ๋ก value๊ฐ์ ๊ฐ์ ธ์ setStyle์ execCommand ํจ์์ ์ ๋ฌํด์ค๋ค. ๊ทธ๋ ๊ฒ execCommand์์ html ๋ฌธ์์ด๋ก ํด๋น ํจ๊ณผ๋ค์ ์ฒ๋ฆฌํ๊ฒ ๋๋ค. ์๋ ์ฝ๋๋ ์์ ๊ณ ์์ ์ ์ ์ฉํ ์ฝ๋๋ค์ด๋ค.
๊ทธ๋ ๋ค๋ฉด ์ด์ ๊ฐ ํจ์๋ค์ ์ญํ ๋ค์ ์ดํด๋ณด์. ์๋ ์ค๋ช ์์ ์์ธํ ์ฝ๋๋ ๋๋ณด๊ธฐ๋ก ํ์ธํ์.
* foucsEditor
const focusEditor = () => {
editorRef.current.focus({ preventScroll: true });
};
์ฌ๊ธฐ์ editorRef.current.focus({ preventScroll: true });๋ editorRef์ current ์์ฑ์ ํตํด ์ค์ DOM ์์์ ์ ๊ทผํ๊ณ focus() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ํด๋น DOM ์์์ ํฌ์ปค์ค๋ฅผ ์ค์ ํ๋ค. ์ด๋ preventScroll: true ์ต์ ์ ์ฌ์ฉํ์ฌ ํฌ์ปค์ค๋ฅผ ์ค์ ํ ๋ ์คํฌ๋กค์ ๋ฐฉ์งํ๋ค. ์ฆ, foucsEditor ํด์ด ์ ์ฉ๋์ด ์๋ ํจ์๋ค์ editorRef๊ฐ ์ฐธ์กฐ ๋๊ณ ์๋ contentEditable์ ๋ดํฌํ๊ณ ์๋ divํ๊ทธ์ ๋ชจ๋ ํฌ์ปค์ค๊ฐ ๋๋ค๋ ๊ฒ์ด๋ค. ๋ฐ๋ผ์ ์์ ๋ชจ๋ ํจ์๋ค์ด ๋์ํ๊ฒ ๋๋ฉด ํด๋น div๋ก ํฌ์ปค์ค๊ฐ ์ฎ๊ฒจ ์ง๋ค๋ ๊ฒ์ด๋ค. ๋ ๋์๊ฐ ์ด๊ฒ์ด ์์ฑ๋๋ ๋จ๊ณ๋ฅผ ๊ฑฐ์น๊ฒ ๋๋ค๋ฉด ๋ฐฐ์ด๊ณผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์งํ์ด ๋ ๊ฒ์ด๋ค.
* setStyle
function setStyle(style) {
document.execCommand(style);
focusEditor();
}
์ด ์ฝ๋๋ document.execCommand() ํจ์๋ฅผ์ฌ์ฉํ์ฌ ์ง์ ๋ ์คํ์ผ์ ์๋ํฐ ์ปดํฌ๋ํธ์ ์ ์ฉํ๋ค. style ๋งค๊ฐ๋ณ์๋ ํด๋น ์คํ์ผ์ HTML๋ฌธ์์ด ์๋ณ์๋ฅผ ๋ฐ๋๋ค. ์๋ฅผ ๋ค์ด, 'bold', 'italic', 'underline' ๋ฑ์ ์คํ์ผ์ด ๋ ์ ์๋ค. document.execCommand() ๋ฉ์๋๋ ๋ธ๋ผ์ฐ์ ๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ๊ณตํ๋ ํธ์ง ๋์์ ์คํ์ํค๋ ํจ์๋ก ์ด๋ฅผ ํตํด ์ฌ์ฉ์๊ฐ ์ฌ๋ฌ ์คํ์ผ๋ค์ ๋ณ๊ฒฝํ๋ ๋ฑ์ ์์ ์ ์ํํ ์ ์๋ค. ๋ค๋ง ์ฌ๊ธฐ์ ๊ฑธ๋ฆฌ๋ ๊ฒ์ด ์๋ค๋ฉด execCommad()๋ ๊ณต์๋ฌธ์ MDN์์ ์ฌ์ฉ์ ๊ถ์ฅํ์ง ์๊ณ ์๋ค. ํ์ฌ ์ด ๋ถ๋ถ ๋๋ฌธ์ ๊ณจ์น๊ฐ ์ํ์ง๋ง ํด๊ฒฐ ๋ฐฉ์์ด ์ ํ ์๋ ๊ฒ์ ์๋๋ค. execCommand์ ๊ดํด์๋ ์์ธํ ๋ด์ฉ์ ๋ฐ๋ก ํฌ์คํ ์ ์ฌ๋ ค ๋๋๋ก ํ๊ฒ ๋ค.
* handleToolClick
const handleToolClick = (e) => {
const element = e.currentTarget.value;
console.log(element);
setStyle(element);
focusEditor();
}
handleToolClick ํจ์๋ ์ฌ์ฉ์๊ฐ ํธ์ง ๋๊ตฌ๋ฅผ ํด๋ฆญํ์ ๋ ์คํ๋๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ด๋ค. ์์ ์ค๋ช
์ ํ์ง๋ง ํด๋น ๋ฒํผ์ ํด๋ฆญ์ ํ์ ๋ ํด๋น ๋ฒํผ์ value๊ฐ์ setStyle ํจ์์ ๋งค๊ฐ๋ณ์๋ก ๋๊ฒจ์ฃผ๋ ํจ์์ด๋ค. ์ฌ๊ธฐ์ ์ฃผ๋ชฉํด์ผํ ๊ฒ์ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ ๋ฐฉ์์ธ๋ฐ ๋ณดํต e.target.value๋ฅผ ์ฌ์ฉํ ๋ฒํ์ง๋ง ์ด ์ฝ๋์์๋ e.currentTarget.value๋ฅผ ์ฌ์ฉํ๊ฒ ๋์๋ค. ๊ทธ ์ด์ ๋ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ์์์ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๋ ์์๊ฐ ๋์ผํ ๊ฒฝ์ฐ์๋ e.currentTarget๊ณผ e.target์ด ๋์ผํ๊ฒ ๋์ํ๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋ฌ๋ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ด ๋ฐ์ํ๋ ๊ฒฝ์ฐ์๋ e.target์ด ์ค์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ์์๋ฅผ ์ฐธ์กฐํ์ง๋ง e.currentTarget์ ํญ์ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๋ ์์๋ก ์ฐธ์กฐํ๋ค. ์ฆ, e.target์ ํด๋ฆญ์ด๋ ๋ง์ฐ์ค ์ด๋ฒคํธ์์๋ ์ฌ์ฉ์๊ฐ ํด๋ฆญํ ์์๋ฅผ ๊ฐ๋ฆฌํค๋ฉฐ ์
๋ ฅ ํ๋์์๋ ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ๊ฐ์ด ์๋ ์์๋ฅผ ๊ฐ๋ฆฌํจ๋ค. e.currentTarget์ ์ด๋ฒคํธ๋ฅผ ํ์ฌ ์ฒ๋ฆฌ ์ค์ธ ์์, ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ์ค์ ๋ก ์ฐ๊ฒฐ๋ ์์๋ฅผ ๊ฐ๋ฆฌํค๋ ๊ฒ์ด๋ค. (์ค๋ช
์ด ์กฐ๊ธ ๋ฏธํกํ๋ค๊ณ ์๊ฐ ๋๋ค.)
๋ฐ๋ผ์ ์กฐ๊ธ ๋ ๋ช
์์ ์ผ๋ก ๋ฒํผ๋ค์ value ๊ฐ์ ๊ตฌ๋ณ ํ๊ธฐ ๋๋ฌธ์ currentTarget์ด ๋ง๋ค๊ณ ํ๋จ๋์ด ์ด๋ ๊ฒ ์ฝ๋๋ฅผ ์์ฑํ๊ฒ ๋๊ฒ์ด๋ค. ์ด๋ฒคํธ ๋ฒ๋ธ๋ง ๋ฌด์์ธ์ง ์๊ณ ์ถ์ผ๋ฉด ์๋ ๋๋ณด๊ธฐ๋ฅผ ํ์ธํ์.
## ์ด๋ฒคํธ ๋ฒ๋ธ๋ง ์ด๋?
์ผ๋ฐ์ ์ผ๋ก HTML ๋ฌธ์์ ์์๋ ๋ถ๋ชจ-์์ ๊ด๊ณ๋ก ๊ตฌ์ฑ๋์ด ์๋ค. ์ด๋ ์์ ์์์์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด, ํด๋น ์ด๋ฒคํธ๋ ์์ ์์์์ ์์๋ก ์ฌ๋ผ๊ฐ๋ฉฐ ๊ฐ ๋ถ๋ชจ ์์๋ก ์ ๋ฌ๋๋ค. ์ด๋ฌํ ์ด๋ฒคํธ ์ ํ ๊ณผ์ ์ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ด๋ผ๊ณ ํ๋ค. ๊ฐ๋จํ ์์๋ฅผ ๋ค์ด๋ณด๋ฉด ์๋์ ๊ฐ์ HTML ๊ตฌ์กฐ๊ฐ ์๋ค๊ณ ๊ฐ์ ํด๋ณด์
<div id="parent">
<div id="child">Click me!</div>
</div>
์ด๋ #child ์์์ ํด๋ฆญ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด, ์ด๋ฒคํธ๋ #child์์ ์์ํด์ #parent๋ก ์ ํ๋๋ค. ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ DOM ํธ๋ฆฌ์ ์์ ์์๋ก ์ด๋ฒคํธ๊ฐ ์ ํ๋๋ ๊ณผ์ ์ ์๋ฏธํ๋ค. ์ฆ, ์์์์์๋ง ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ๋ฐ์๋๊ฒ ํ๊ณ ์ถ์ง๋ง ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ด ๋ฐ์ํ๊ฒ๋๋ฉด ๋ถ๋ชจ๊น์ง ํจ๋ค๋ง ํ๊ฒ ๋๋ ํผ์น ๋ชปํ๋ ์ํฉ๊น์ง ๋๋ฌ ํ๊ฒ ๋๋ ๊ฒ์ด๋ค.
* handleImgToolClick
const imageSelectorRef = useRef(null); // ํ์ผ ์ ํ input ์์์ ๋ํ ์ฐธ์กฐ
...
const handleImgToolClick = () => {
// ํ์ผ ์ ํ input์ ํด๋ฆญํ๋ค.
imageSelectorRef.current.click();
}
handleImgToolClick ํจ์๋ ์ด๋ฏธ์ง ๋๊ตฌ๋ฅผ ํด๋ฆญํ์ ๋ ํ์ผ ์ ํ input ์์๋ฅผ ํด๋ฆญํ์ฌ ์ฌ์ฉ์๊ฐ ์ด๋ฏธ์ง๋ฅผ ์ ํํ ์ ์๋๋ก ํ๋ ์ญํ ์ ์ด๋ค. ์ฌ์ฉ์๊ฐ ์ด๋ฏธ์ง ๋๊ตฌ๋ฅผ ํด๋ฆญํ๋ฉด ํ์ผ ์ ํ input ์์๊ฐ ์๋์ผ๋ก ํด๋ฆญ๋์ด ํ์ผ์ ์ ํํ ์ ์๋ ์ฐฝ์ด ์ด๋ฆฌ๊ฒ ๋๋ค. ๊ตฌ์ฒด์ ์ผ๋ก ์กฐ๊ธ ๋ ์ค๋ช ํ์๋ฉด imageSelectorRef.current.click()๋ imageSelectorRef๋ผ๋ Ref ๊ฐ์ฒด์ current ์์ฑ์ ํตํด ํ์ฌ DOM ๋ ธ๋์ ์ ๊ทผํ๊ณ ๊ทธ DOM ๋ ธ๋์ click() ๋ฉ์๋๋ฅผ ํธ์ถํ๋ค. ์ด๋ ์ค์ ๋ก ํ์ผ ์ ํ input ์์๋ฅผ ํด๋ฆญํ๋ ๊ฒ๊ณผ ๊ฐ์ ๋์์ ์ํํ๋ค.
์ฐ์ ์ฌ๊ธฐ ๊น์ง๊ฐ ๊ธฐ๋ณธ ํด๋ฐ๋ค์ ์ ์ํ ๊ณผ์ ์ด๋ค. ๋ค์ ํฌ์คํ ์์๋ ์ด๋ฏธ์ง๋ฅผ ๊ฐ์ ธ์ค๋ ๋ถ๋ถ์ ๋ค๋ฃจ์ด ๋ณผ ๊ฒ์ด๋ค.