본문으로 바로가기

contenteditable의 newline 처리하기

category React 2021. 5. 3. 14:22

contenteditable 속성으로 만든 write라는 이름을 가진 div에 글을 작성하고 그 write에서 innerText를 뽑아온 후

임의의 가공을 거쳐 다시 view라는 이름을 가진 div를 통해서 사용자에게 보여주는 로직을 구현하는 것이 목표인 상황

파싱

우선 우리가 가져온 innertText는 태그를 포함하고 있지 않고 따라서 태그를 포함시켜서 view로 보낼 수가 없다

이런식으로 처리할까 생각도 했었지만 그냥 라이브러리의 힘을 빌리기로 했다

 

html태그가 포함된 문자열 렌더링하기

위의 네모의 텍스트를 innerHTML로 추출한 뒤 그 상태값을 그대로 렌더링한 결과를 밑에 나타내고 있다 그런데 왜 태그를 html처럼 나타내지않고 그대로 문자열로 나타낼까? 궁금해서 찾아봤다 보

code-anthropoid.tistory.com

ReactHtmlParser라는 라이브러리인데

 

react-html-parser

Parse HTML into React components

www.npmjs.com

태그가 포함된 문자열을 아주 편하게 렌더링할 수 있게 도와준다

사용법

const Test = () => {
    const html = '<div>Example HTML string</div>';
    const reactHtml = ReactHtmlParser(html);
    return (
        <div>
            {reactHtml}
        </div>
    );
};

newline

이제 뽑아온 innerTEXT에 스타일이 적용된 태그를 넣거나 하는 방식으로 꾸며진 view를 사용자에게 보여주면된다

contenteditable에서 엔터를 쳐서 newline을 만들면 각 브라우저마다 다르게 DOM을 생성하는데

크롬의 경우

<div>
  <br>
</div>

로 하나의 공백 줄을 생성하고 이 때의 DOM을 innerTEXT로 뽑아오면

""
""

로 공백 두 줄을 생성한다 아마 비어있는 태그가 두 개라서 줄바꿈 문자 두 개를 뽑아오는 것 같은데 자세히는 모르겠다

이러한 이유 때문에 문자열을 ReactHtmlParser에 넣고 렌더링하면

write박스에서 엔터 한 번 누를 때 마다 view박스에서는 두 개의 빈 줄이 생긴다

뭔소린가 싶겠지만 그림을 보면 알 수 있다

위의 contenteditable가 붙은 div는 write 기능을 하는데

4번의 엔터를 쳐서 4개의 newline을 만들었고 하나의 newline을 표현하기위해 br태그를 div로 둘러싸고 있는 모습이다

아래의 div는 view 역할을 하고 있고 String 이후에 빈 줄을 잘 표현하고 있는 것 같지만..

newline에 공백 대신 a를 넣게되는 순간 확연하게 줄어든 view의 크기를 볼 수 있다

공백일 때 존재했던 br은 값이 입력되는 순간 없어지고 div태그안에 a만 들어가게되어서 두 배의 출력이 아닌 정상적인 출력을 한다

해결 방법

사용자에게 보여지는 과정은 다음과 같다

write에 enter입력 -> div와 br 태그 생성 -> innerTEXT로 추출(여기서 두 배로 뻥튀기) -> ReactHtmlParser를 통해 변환 -> 렌더링 -> view에 출력

어짜피 추출해온 데이터는 Redux의 store에 넣어 관리하고 다시 store에서 ReactHtmlParser에 전달해 줄 예정이다

innerTEXT로 추출(여기서 두 배로 뻥튀기) -> 추출한 데이터를 수정 -> ReactHtmlParser를 통해 변환

과정을 하나 추가하기로 했다

    const text = e.target.innerText.replaceAll('\n\n','\n');
    dispatch(changeExample(text));

이거 해결한다고 몇 시간은 골 싸맸는데 정작 코드 한 줄이면 해결 할 수 있었다..