-
DOM 조작 - 텍스트 노드에 대한 접근 / 수정 2프론트엔드/DOM 2020. 10. 16. 12:16
'DOM'에서 텍스트 노드에 접근하는 방법은 굉장히 다양하다.
예전 올린 글에선 'DOM'의 텍스트 노드에는 'nodevalue'를 이용한다고 했다.
위와 같은 내용의 'HTML' 문서가 있다고 가정해보자.
해당 'HTML'의 코드는 다음과 같다.
<body> <p id="nodevalue"> 테스트입니다. </p> </body>
이때 텍스트 노드에 접근하기 위해선 다음과 같이 하면 된다.
<script> let nodev = document.getElementById('nodevalue'); console.log(nodev.firstChild.nodeValue); // '테스트입니다' 출력 </script>
어렵지 않게 텍스트 노드의 값을 구할 수 있지만 이런 경우 문제가 생긴다.
1. nodevalue의 문제점
위와 같은 'HTML' 화면이 있다고 가정해보자. 코드는 아래와 같다.
<body> <p id="nodeval"> 테스트1 <br> 테스트2 </p> </body>
이때 위에서 한 것과 같이 <p> 태그의 내용을 선택해보자.
<script> let nv = document.getElementById('nodeval'); console.log(nv.firstChild.nodeValue); </script>
코드의 결과는 다음과 같다.
원하는 결과와 다른 결과가 나왔다.
'nodeValue'를 이용할 경우 'nodeValue'는 텍스트 노드만 따로 구분하는 것이 아니다.
해당 요소 노드의 모든 노드를 탐색하게 된다.
<p> 태그 중간에 <br> 태그가 들어감으로써 <p> 태그 아래 텍스트 노드만 불러오는 것에 실패한 것이다.
그래서 우리가 원하는 결과를 얻으려면 다음과 같이 코드를 써야 한다.
<script> let nv = document.getElementById('nodeval'); console.log(nv.firstChild.nodeValue+nv.lastChild.nodeValue); // '테스트1 테스트2' 출력 console.log(nv.firstChild.nodeValue+nv.firstChild.nextSibling.nextSibling.nodeValue); // '테스트1 테스트2' 출력 </script>
결과물은 다음과 같다.
원하는 결과는 얻었지만 얻어내는 과정이 한 눈에 봐도 복잡하다.
2. textContent, innertext, innerHTML
위에서 말한 'nodevalue'로 요소 노드의 텍스트 노드에 접근하는 것은 힘들다.
더 간단한 방법을 알아보자.
아까와 같은 텍스트가 있다고 가정해보자.
코드는 조금 다르다.
<body> <p id = "text"> 텍스트1 <br> 텍스트2 <p> </body>
이번엔 'nodevalue'를 쓰는 것보다 간단하게 접근해보자.
여기선 각각 'textContent', 'innerText', 'innerHTML'을 쓸 예정이다.
<script> let test = document.getElementById('text'); console.log("textContent 결과물 : " + test.textContent); console.log("innerText 결과물 : " + test.innerText); console.log("innerHTML 결과물 : " + test.innerHTML); </script>
콘솔창에 나온 결과물은 다음과 같다.
우선 'nodevalue'와 달리 가져오고 싶은 결과물은 다 얻어내긴했다.
다만 세 가지가 형태가 모두 제각각이다.
이제는 각 프로퍼티에 대해서 알아보자.
(1) textContent
'textContent'는 그 의미대로 선택된 요소 노드에 존재하는 텍스트값만 따로 얻어낸다.
중간에 다른 태그가 들어가도 선택된 요소 노드의 하위의 텍스트값을 전부 다 가져온다.
(2) innerText
'innerText'는 'text Content'와 마찬가지로 선택된 요소 노드에 존재하는 텍스트값만 따로 가져온다.
다만 CSS에 순종적이고 textContent에 비해 속도가 느리다.
(3) innerHTML
'innerHTML'는 선택된 요소 노드에 존재하는 텍스트 뿐 아니라 모든 내용을 문자열로 얻을 수 있다.
위의 예시에서도 볼 수 있듯 선택된 요소 노드 하위의 마크업(태그)까지 가져온 것을 볼 수 있다.
이렇게 세 가지를 적절히 이용하면 요소 노드의 컨텐츠(텍스트뿐 아니라)를 쉽게 얻어낼 수 있다.
다만 세 가지 중에서 'innerHTML'의 경우 사용에 주의가 필요하다.
3. 컨텐츠 쓰기
우리는 지금까지 기존에 이미 써져있는데 요소 노드의 컨텐츠를 얻어내는 내용을 공부했다.
즉 이미 쓴 내용을 읽어들이는 과정을 공부한 것이다.
하지만 반대로 특정 요소 노드에 사용자가 쓴 텍스트를 집어넣거나 할 땐 어떻게 해야할까?
쓰기 과정은 읽는 과정과 반대로 진행하면 된다.
아래와 같은 코드가 있다고 가정하자.
참고로 아래 코드로는 아무 내용도 없고 이제 여기에 컨텐츠가 있는 <p>태그를 추가할 것이다.
<body> <div class="container"></div> </body>
아무 내용도 없는 상황에서 컨텐츠를 추가하려면 다음과 같이 하면 된다.
<script> let con = document.getElementsByClassName('container')[0]; function apc(text){ let p = document.createElement('p'); p.textContent = text; con.appendChild(p); } function inner(text){ let p = document.createElement('p'); p.innerHTML = text; con.append(p); } apc("<span style = 'color: red'> textContent테스트입니다. </span>"); inner("<span style = 'color: red'> inner테스트입니다. </span>"); </script>
해당 내용은 'textContent'와 'innerHTML'를 이용해서 HTML 파일에 내용을 추가하는 함수와 실행결과다.
참고로 함수 내용을 설명하자면 다음과 같다.
- <p> 요소 노드를 생성한다.
- 파라미터로 받는 텍스트를 <p> 요소 노드의 컨텐츠로 삽입한다.
- <p> 요소를 <div>값에 추가해준다.
그 결과물은 다음과 같다.
위는 'textContent'의 결과물이고 아래는 'innerHTML'의 결과물이다.
위에서 배웠듯 'textContent'는 선택된 요소 노드의 텍스트만 얻어낸다.
'innerHTML'은 선택된 노드 요소 노드의 컨텐츠는 물론이고 각종 태그까지 다 얻어낸다.
이는 쓰기를 할 때도 마찬가지다.
함수를 통해 태그 내용이 포함된 텍스트를 전달할 경우 'textContent'는 그 내용을 텍스트 그대로 처리한다.
반면 'innerHTML'은 해당 텍스트를 태그 부분과 텍스트 부분으로 나눠서 처리한다.
그래서 'innerHTML'을 통해 입력한 텍스트는 위와 같이 스타일이 적용되어 텍스트가 출력된 것이다.
얼핏보면 'innerHTML' 편해보이지만 이를 함부로 쓰면 큰 문제를 일으킬 수 있다.
4. 'innerHTML'의 부작용
앞서 말했듯 'innerHTML'은 쓰기 과정을 진행할 때 텍스트로 입력한 태그라도 태그로 분류해서 실행한다.
아래와 같은 코드가 쓰여있는 상황을 가정하자.
<body> <div class="container"></div> </body>
이때 'innerHTML'을 통해 HTML 문서에 내용을 추가하는 함수를 만들고 다음과 같은 텍스트를 추가해준다.
<span style = 'color: red'> inner테스트입니다. </span>
<script> let con = document.getElementsByClassName('container')[0]; function inner(text){ let p = document.createElement('p'); p.innerHTML = text; con.append(p); } inner("<span style = 'color: red'> inner테스트입니다. </span>"); </script>
결과물은 다음과 같다.
'textContent'와 달리 텍스트로 입력한 태그까지 전부 진짜 태그로서 처리했다.
이는 읽기 과정에선 문제가 없지만 사용자 입력을 받는 사이트라면 문제가 생길 수 있다.
즉 사용자가 문제가 있는 코드를 'innerHTML'을 통해 페이지 내에 삽입할 가능성이 생기기 때문이다.
만약 텍스트를 'textContent'로 처리할 경우 태그 부분도 텍스트로 처리한다.
그렇기 때문에 어떤 코드를 심으려고해도 텍스트로서만 실행된다.
반면 'innerHTML'은 사용자가 특정 태그를 마음대로 실행시킬 수 있어서 보안에 문제가 생길 수 있다.
그래서 가급적이면 사용자 입력을 받을 땐 'innerHTML' 사용은 주의해야 한다.
'프론트엔드 > DOM' 카테고리의 다른 글
DOM 조작 - 컨텐츠 추가하기 (0) 2020.10.16 DOM 조작 - 속성 노드의 생성, 수정, 삭제 2 (0) 2020.10.16 DOM 조작 - 속성 노드의 생성, 삭제 (0) 2020.10.16 DOM 조작 - 텍스트 노드에 대한 접근 / 수정 (0) 2020.10.13 DOM - 노드의 관계를 통한 접근 (0) 2020.10.07