\(@^0^@)/

[TIL] 바닐라 자바스크립트로 글쓰기 에디터를 만들어보자. 본문

TIL

[TIL] 바닐라 자바스크립트로 글쓰기 에디터를 만들어보자.

minjuuu 2022. 7. 22. 19:50
728x90

글쓰기 에디터

에디터를 구현하려면, Document.execCommand()에 대해 알아야 한다.

Document.execCommand()

HTML 문서가 designMode로 전환되면 문서에서 execCommand 메서드를 사용할 수 있게 되는데 이것을 이용해서 문서의 편집 가능한 영역을 변경할 수 있다.

문법
bool = document.execCommand(aCommandName, aShowDefaultUI, aValueArgument)
  • aCommandName
    • 실행해야 할 명령어 이름 DOMString을 나타냅니다. 사용 가능한 명령어 목록은 Commands를 참고하세요.
  • aShowDefaultUI
    • 기본 사용자 UI가 나타나야 하는지를 보여주는 Boolean 값입니다. Mozilla에서는 구현되어 있지 않습니다.
  • aValueArgument
    • 입력 변수가 필요한 명령어(insertImage와 같이 삽입할 이미지의 URL이 필요한)의 경우 이 DOMString으로 정보를 전달합니다. 변수가 필요하지 않으면 null을 표기합니다.

나는 여러 명령어 중, 몇 개만 사용해보려 한다.

  • backColor
    • 문서의 배경색을 변경합니다. styleWithCss 모드에서는 대신 상위 요소의 배경색에 영향을 미칩니다. 변수 값으로 <color> 값을 넘겨야 합니다. Internet Explorer는 이 명령어를 텍스트 배경색을 변경하는 데 사용합니다.
  • bold
    • 선택 영역이나 입력 위치에 볼드를 온/오프 합니다. Internet Explorer는 <b> 대신 <strong> 태그를 사용합니다.
  • fontSize
    • 선택 영역이나 입력 위치의 서체 크기를 변경합니다. 변수 값으로 HTML 서체 크기(1-7)를 넘겨야 합니다.
  • foreColor
    • 선택 영역이나 입력 위치의 서체 색상을 변경합니다. 변수 값으로 색상 값 문자열을 넘겨야 합니다.
  • selectAll
    • 편집 가능 영역의 모든 내용을 선택합니다.
  • delete
    • 현재 선택 영역을 지웁니다.
  • undo
    • 직전에 실행된 명령을 취소합니다.
  • insertOrderedList
    • 선택 영역이나 입력 위치에 번호 순서가 있는 목록을 넣습니다
  • insertUnorderedList
    • 선택 영역이나 입력 위치에 번호 순서가 없는 목록을 넣습니다.

1. 별도의 commands 파일 만들어서 script파일에 import 하기

js에서는 import, export 해줄 때 module화를 해야 하는 것을 주의!


 

2. command 객체 안의 label 값들을 렌더 시키기

import 한 commands를 함수 안에서 map을 돌려서 하나씩 뿌려주는데,
1) 그 안에서 클릭이벤트를 걸어 명령어를 다루기 위한 함수 setCommand를 생성한다.
2) button 요소를 동적 생성하여 명령어 command 객체 안의 label을 innerText로 넣고, 지정한 레이아웃에 append 해준다.

const init = () => {
    commands.map((command) => {
      const element = document.createElement('button')
      element.innerText = command.label
      element.addEventListener('click', (e) => {
        e.preventDefault()
        setCommand(command)
      })
      editorButtons.appendChild(element)
    })
  }
  
init()

버튼 안에 command의 label이 알맞게 들어와 진 것을 볼 수 있다.


3. setCommand 함수에서 Document.execCommand() 처리하기

init함수에서 setCommand함수로 넘겨준 인자를 받아서 cmd, val, label의 변수에 각각 할당해준다.
가끔 가다가 val이 없는 기능들이 있는데, (예를 들면 굵기는 설정값 필요 없이 그냥 굵게만 해주면 되는 기능)
값이 없어서 undefined일 경우 빈 값을 넘겨주고, 값이 있을 경우 사용자가 프롬프트에 값을 입력하면 그 값을 받아오자.

받아온 값을 exeCommand에 넣어줄 차례.
문법에 맞게 첫 번째 인자에 commandName을, 두 번째는 false, 세 번째엔 사용자가 설정한 val값을 넣어준다.

const setCommand = (command) => {
    let cmd = command.cmd
    let val = command.val
    let label = command.label

    let setVal =
      typeof val !== 'undefined'
        ? prompt(label + '를 입력해주세요 (영어 또는 숫자)', val)
        : ''
    document.execCommand(cmd, false, setVal || '')
  }


4. 마지막으로 에디터, HTML 보기 버튼 설정하기

쿼리 셀렉터로 불러낸 두 요소들에 함수를 걸어준다.
"HTML 보기" 일 경우 editorhtml 클래스에 show을 추가하고, "에디터 보기" 일 경우 editorEdit 클래스에 show를 추가한다.

텍스트를 작성할 경우, 화면에 나타나는 기본값이 editorEdit 클래스이기 때문에 "HTML 보기"에는 내가 입력한 텍스트의 값이 전달되지 않는다. 따라서, editorHtml에. innerText에 edtiorEdit.innerHTML의 값을 넘겨주어야 한다.

const onClickShowButton = (e) => {
    if (e.target.innerText === 'HTML 보기') {
      let textContent = editorEdit.innerHTML
      editorHtml.innerText = textContent
      editorHtml.classList.add('show')
      editorEdit.classList.remove('show')
    } else if (e.target.innerText === '에디터 보기') {
      editorEdit.classList.add('show')
      editorHtml.classList.remove('show')
    }
  }


구현하는 과정에 있어서, 코드를 더 간결하게 짤 수 있을 것 같단 생각으로 코드를 여러 번 수정하였는데 처음보다는 많이 간결해졌지만, 수정하지 못하고 막히는 부분들이 많았다. 아직 많이 부족해서 그런 것 같다는 생각뿐이다.
어떻게 하면 간결하고 가독성이 좋은 코드를 짤지 꾸준히 생각한다면, 분명 더 성장하는 개발자가 될 수 있을 것 같다.
지금은 우선 이런 생각을 하고 있다는 것에 위안을 두고... 더더 공부하자!

[ 출처 : 프로젝트로 배우는 JavaScript ]

728x90