스크립트에서 수정 기호를 선택한 채로 어떤 단어를 클릭하면 수정 가능하도록 하는 기능을 구현해야 했다. 클릭 이벤트를 감지해서 input text를 단어 위에 띄우고 고생하고 있었는데(input을 띄우면 기존 기능들이 적용이 안 됐다) contentEditable이라는 옵션이 있다는 걸 알게 되었다.
https://developer.mozilla.org/ko/docs/Web/HTML/Global_attributes/contenteditable
contenteditable - HTML: Hypertext Markup Language | MDN
contenteditable 전역 특성은 사용자가 요소를 편집할 수 있는지 나타내는 열거형 특성입니다.
developer.mozilla.org
<span contenteditable="true">
수정 가능한 텍스트
</span>
위와 같이 옵션을 주면 사용자가 클릭했을 때 바로 수정이 가능하다(우와).
나는 아래와 같이 사용했다.
<Text
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault(); // 줄바꿈 방지
}
}}
onInput={(e) => {
console.log("수정 후: ", e.target.innerText);
edited[i] = e.target.innerText; // 수정 후 단어를 edited에 저장
setEdited([...edited]);
}}
contentEditable={cursor === edit} // 현재 커서가 수정펜일 때만 수정 모드
spellCheck={false}
suppressContentEditableWarning={true} // warning 무시..
>
우선 onKeyDown() 이벤트에서 엔터 키를 눌렀을 때 줄바꿈이 되지 않도록 했다(서비스 기능 상 필요).
그리고 onInput()으로 텍스트가 바뀔 때마다 업데이트 했는데, onChange()는 input, textarea, select 같은 엘리먼트에서만 작동하기 때문이다.
conteneEditable 옵션은 내가 원하는 상황에서만 켜지도록 설정하고 spellCheck를 false로 설정해 사용자의 입력에 대한 맞춤법 검사는 하지 않았다.
이렇게 리액트 컴포넌트 안에 contentEditable 옵션을 넣으면 "A component is contentEditable and contains children managed by React"이라는 콘솔 워닝이 뜨는데, 뭐 컴포넌트 안의 내용이 변할 수 있고 그 책임은 너한테 있다는 내용이다. 내가 원하는 기능이 컴포넌트 안의 내용 변화기 때문에, suppressContentEditableWarning을 설정해 워닝을 무시했다.
++ 저렇게 했더니 텍스트가 변할 때마다 edited state가 다시 렌더링 되면서 delete가 제대로 동작하지 않길래 다음과 같이 수정했다.
onBlur={(e) => {
console.log("수정 후: ", e.target.innerText);
edited[i] = e.target.innerText; // 수정 후 단어를 edited에 저장
setEdited([...edited]);
}}
onBlur() 이벤트는 사용자가 input field를 벗어났을 때 작동한다. 편집이 끝나고 다른 곳으로 포커스를 이동하게 되면 수정된 최종 단어를 저장하도록 수정했다.
수정 전 단어를 보여주기 위해서는 툴팁을 제작했다.
const OriginalText = styled.span`
visibility: hidden;
// 디자인 및 위치
${Text}:hover & {
visibility: visible;
}
// 아래 화살표 디자인
&::after {
content: " ";
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: grey transparent transparent transparent;
}
`;
툴팁까지 예쁘게 만들어 주고 나면 수정 기능 완성!
'JS & CSS & HTML' 카테고리의 다른 글
JS e.target vs e.currentTarget (미스터리 해결기...) (1) | 2023.07.20 |
---|---|
JS sort (문자열 배열 정렬 & 숫자 배열 정렬) (0) | 2022.06.26 |
JS Image preloading (0) | 2022.05.31 |
CSS transform: translate vs. absolute positioning (0) | 2022.05.31 |
CSS line-height (0) | 2022.05.03 |