반응형
textContent의 근본 개념
textContent
는 노드와 그 자손들의 텍스트 콘텐츠를 순수 텍스트로 표현한 것입니다. HTML 태그는 모두 제거하고 오직 텍스트만 추출하거나 설정하는 속성입니다.
const div = document.createElement('div');
div.innerHTML = '<p>Hello <strong>World</strong>!</p>';
// textContent는 모든 텍스트만 추출
console.log(div.textContent); // "Hello World!"
// innerHTML은 HTML 구조 포함
console.log(div.innerHTML); // "<p>Hello <strong>World</strong>!</p>"
주요 사용 케이스
1. 안전한 텍스트 삽입 (XSS 방지)
사용자 입력을 받을 때 가장 중요한 용도입니다:
// ❌ 위험: 사용자가 스크립트를 삽입할 수 있음
userComment.innerHTML = userInput; // "<script>alert('해킹!')</script>" 실행됨
// ✅ 안전: HTML로 해석되지 않고 순수 텍스트로 표시
userComment.textContent = userInput; // 스크립트가 문자 그대로 표시됨
2. 텍스트만 추출하기
HTML 구조에서 순수 텍스트만 필요할 때:
// 복잡한 HTML 구조에서 텍스트만 추출
const article = document.querySelector('article');
const plainText = article.textContent; // 모든 태그 제거, 텍스트만
// 예: 글자 수 세기
const charCount = article.textContent.length;
// 예: 검색 기능
if (article.textContent.includes('JavaScript')) {
// 해당 article에 'JavaScript' 단어가 포함됨
}
3. 간단한 텍스트 업데이트
HTML 구조가 필요 없이 텍스트만 변경할 때:
// 버튼 텍스트 변경
button.textContent = '로딩중...';
// 에러 메시지 표시
errorDiv.textContent = '입력값이 올바르지 않습니다.';
// 카운터 업데이트
counterSpan.textContent = count.toString();
4. 텍스트 노드 직접 조작
// 텍스트 노드의 내용 변경
const textNode = element.firstChild; // 첫 번째 텍스트 노드
if (textNode.nodeType === Node.TEXT_NODE) {
textNode.textContent = '새로운 텍스트';
}
textContent vs innerHTML vs innerText
const div = document.createElement('div');
div.innerHTML = `
<p>보이는 텍스트</p>
<p style="display:none">숨겨진 텍스트</p>
`;
// innerHTML: HTML 태그 포함
console.log(div.innerHTML); // 전체 HTML 구조
// textContent: 모든 텍스트 (숨겨진 것 포함)
console.log(div.textContent); // "보이는 텍스트숨겨진 텍스트"
// innerText: 실제로 보이는 텍스트만
console.log(div.innerText); // "보이는 텍스트"
실전 예시: 댓글 시스템
function addComment(userInput) {
const comment = document.createElement('div');
// 사용자 입력을 위한 별도 요소 생성
const textContainer = document.createElement('p');
textContainer.textContent = userInput; // XSS 방지
// 시간 정보 요소 생성
const time = document.createElement('span');
time.className = 'comment-time';
// small 요소도 DOM으로 생성 (더 안전)
const small = document.createElement('small');
small.textContent = new Date().toLocaleString();
time.appendChild(small);
// 조립
comment.appendChild(textContainer);
comment.appendChild(time);
commentList.appendChild(comment);
}
// 결과 HTML:
// <div>
// <p>사용자의 댓글 내용</p>
// <span class="comment-time">
// <small>2024. 12. 27. 오후 3:30:00</small>
// </span>
// </div>
핵심은 "HTML 태그 해석이 필요한가?"입니다:
- 필요 없음 →
textContent
(더 안전하고 빠름) - 필요함 →
innerHTML
(XSS 위험 주의)
코드 상세 해석
실무에서 자주 쓰는 패턴
function addComment(userInput) {
const comment = document.createElement('div');
comment.className = 'comment-item';
// HTML 템플릿 사용 (신뢰할 수 있는 데이터만)
comment.innerHTML = `
<div class="comment-content"></div>
<span class="comment-meta">
<small class="comment-time">${new Date().toLocaleString()}</small>
</span>
`;
// 사용자 입력은 textContent로 안전하게 삽입
comment.querySelector('.comment-content').textContent = userInput;
commentList.appendChild(comment);
}
XSS 공격 시뮬레이션
// 악의적인 사용자 입력 예시
const maliciousInput = '<img src=x onerror="alert(\'해킹!\')">';
// ❌ innerHTML 사용 시 (위험!)
comment.innerHTML = maliciousInput;
// 결과: 스크립트가 실행되어 alert 창이 뜸!
// ✅ textContent 사용 시 (안전!)
comment.textContent = maliciousInput;
// 결과: "<img src=x onerror="alert('해킹!')">" 텍스트가 그대로 표시됨
완전한 실전 예시
class CommentSystem {
constructor(container) {
this.container = container;
}
addComment(userInput, userId) {
// 입력값 검증
if (!userInput.trim()) {
alert('댓글을 입력해주세요');
return;
}
// 댓글 요소 생성
const comment = document.createElement('article');
comment.className = 'comment';
comment.dataset.timestamp = Date.now();
// 안전한 템플릿 구조
comment.innerHTML = `
<div class="comment-header">
<span class="comment-author"></span>
<time class="comment-time">${this.formatTime(new Date())}</time>
</div>
<div class="comment-body"></div>
<div class="comment-actions">
<button class="btn-like">좋아요</button>
<button class="btn-reply">답글</button>
</div>
`;
// 사용자 입력은 textContent로 안전하게
comment.querySelector('.comment-author').textContent = userId;
comment.querySelector('.comment-body').textContent = userInput;
// 이벤트 리스너 추가
comment.querySelector('.btn-like').addEventListener('click', () => {
this.likeComment(comment);
});
this.container.appendChild(comment);
}
formatTime(date) {
const now = new Date();
const diff = now - date;
if (diff < 60000) return '방금 전';
if (diff < 3600000) return `${Math.floor(diff/60000)}분 전`;
if (diff < 86400000) return `${Math.floor(diff/3600000)}시간 전`;
return date.toLocaleDateString();
}
likeComment(comment) {
comment.classList.toggle('liked');
}
}
// 사용
const commentSystem = new CommentSystem(document.getElementById('comments'));
commentSystem.addComment('좋은 글 감사합니다!', 'user123');
핵심 원칙:
- 사용자 입력 →
textContent
(항상!) - 신뢰할 수 있는 구조 →
innerHTML
(조심스럽게) - 두 가지를 섞을 때는 구조를 먼저 만들고, 사용자 데이터를 나중에 삽입
반응형
'JS_개념' 카테고리의 다른 글
childNodes vs children (0) | 2025.10.14 |
---|---|
childNodes vs children (0) | 2025.09.19 |
2-1-5. Node와 Element의 차이에 대해 설명해주세요 (0) | 2025.09.19 |