AJAX 댓글 시스템¶
페이지 이동 없이 댓글을 작성, 수정, 삭제하는 방법을 학습합니다.
페이지 이동 없는 댓글 작성¶
기본 구조¶
<!-- 댓글 작성 폼 -->
<form action="./" method="post" onsubmit="return procFilter(this, insert_comment)">
<input type="hidden" name="module" value="board" />
<input type="hidden" name="act" value="procBoardInsertComment" />
<input type="hidden" name="document_srl" value="{$oDocument->document_srl}" />
<input type="hidden" name="comment_srl" value="" />
<input type="hidden" name="parent_srl" value="" />
<textarea name="content" rows="4" cols="50"></textarea>
<div class="btnArea">
<button type="submit" class="btn btn-primary">댓글 작성</button>
</div>
</form>
JavaScript 처리¶
// 댓글 작성 후 콜백
function completeInsertComment(ret_obj) {
var error = ret_obj.error;
var message = ret_obj.message;
var document_srl = ret_obj.document_srl;
var comment_srl = ret_obj.comment_srl;
if(error != 0) {
alert(message);
} else {
// 댓글 목록 새로고침
loadCommentList(document_srl);
// 폼 초기화
jQuery('#comment_form')[0].reset();
}
}
// 댓글 목록 불러오기
function loadCommentList(document_srl) {
var params = {
document_srl: document_srl,
cpage: 1
};
exec_xml('board', 'getBoardCommentPage', params, function(ret) {
jQuery('#comment-list').html(ret.html);
});
}
페이지 이동 없는 댓글 수정¶
수정 버튼 추가¶
<div class="comment-item" id="comment_{$comment->comment_srl}">
<div class="comment-content">{$comment->getContent()}</div>
<div class="comment-actions" cond="$comment->isGranted()">
<a href="#" onclick="toggleModifyComment({$comment->comment_srl}); return false;">수정</a>
<a href="#" onclick="deleteComment({$comment->comment_srl}); return false;">삭제</a>
</div>
<!-- 수정 폼 (숨김) -->
<div class="modify-form" id="modify_form_{$comment->comment_srl}" style="display:none;">
<form onsubmit="return modifyComment(this)">
<input type="hidden" name="comment_srl" value="{$comment->comment_srl}" />
<textarea name="content" rows="3">{$comment->getContentText()}</textarea>
<button type="submit">수정</button>
<button type="button" onclick="toggleModifyComment({$comment->comment_srl})">취소</button>
</form>
</div>
</div>
수정 JavaScript¶
// 수정 폼 토글
function toggleModifyComment(comment_srl) {
jQuery('#comment_' + comment_srl + ' .comment-content').toggle();
jQuery('#modify_form_' + comment_srl).toggle();
}
// 댓글 수정
function modifyComment(form) {
var params = {
comment_srl: form.comment_srl.value,
content: form.content.value
};
exec_xml('board', 'procBoardUpdateComment', params, function(ret) {
if(ret.error != 0) {
alert(ret.message);
} else {
// 수정된 내용 반영
jQuery('#comment_' + params.comment_srl + ' .comment-content').html(ret.content);
toggleModifyComment(params.comment_srl);
}
});
return false;
}
페이지 이동 없는 댓글 삭제¶
삭제 함수¶
function deleteComment(comment_srl) {
if(!confirm('댓글을 삭제하시겠습니까?')) return false;
var params = {
comment_srl: comment_srl
};
exec_xml('board', 'procBoardDeleteComment', params, function(ret) {
if(ret.error != 0) {
alert(ret.message);
} else {
// 댓글 항목 제거
jQuery('#comment_' + comment_srl).fadeOut(300, function() {
jQuery(this).remove();
// 댓글 수 업데이트
updateCommentCount();
});
}
});
}
// 댓글 수 업데이트
function updateCommentCount() {
var count = jQuery('.comment-item').length;
jQuery('.comment-count').text('[' + count + ']');
}
대댓글 작성¶
대댓글 폼¶
<div class="reply-form" id="reply_form_{$comment->comment_srl}" style="display:none;">
<form onsubmit="return insertReply(this, {$comment->comment_srl})">
<input type="hidden" name="document_srl" value="{$oDocument->document_srl}" />
<input type="hidden" name="parent_srl" value="{$comment->comment_srl}" />
<textarea name="content" rows="2" placeholder="답글을 입력하세요"></textarea>
<button type="submit">답글 작성</button>
<button type="button" onclick="toggleReplyForm({$comment->comment_srl})">취소</button>
</form>
</div>
대댓글 JavaScript¶
// 답글 폼 토글
function toggleReplyForm(comment_srl) {
jQuery('#reply_form_' + comment_srl).toggle();
}
// 답글 작성
function insertReply(form, parent_srl) {
var params = {
document_srl: form.document_srl.value,
parent_srl: parent_srl,
content: form.content.value
};
exec_xml('board', 'procBoardInsertComment', params, function(ret) {
if(ret.error != 0) {
alert(ret.message);
} else {
// 댓글 목록 새로고침
loadCommentList(params.document_srl);
// 폼 초기화
form.reset();
toggleReplyForm(parent_srl);
}
});
return false;
}
실시간 업데이트¶
자동 새로고침¶
// 30초마다 댓글 목록 새로고침
setInterval(function() {
if(window.document_srl) {
loadCommentList(window.document_srl);
}
}, 30000);
// 새 댓글 알림
function checkNewComments() {
var params = {
document_srl: window.document_srl,
last_comment_srl: getLastCommentSrl()
};
exec_xml('board', 'getNewCommentCount', params, function(ret) {
if(ret.new_count > 0) {
showNewCommentNotification(ret.new_count);
}
});
}
추천/비추천 기능¶
경고창 없이 동작¶
// 댓글 추천
function voteComment(comment_srl, point) {
var params = {
target_srl: comment_srl,
point: point
};
exec_xml('board', 'procBoardVoteUpComment', params, function(ret) {
if(ret.error != 0) {
alert(ret.message);
} else {
// 추천수 업데이트
var voted_count = parseInt(ret.voted_count);
jQuery('#voted_count_' + comment_srl).text(voted_count);
// 버튼 비활성화
jQuery('#vote_button_' + comment_srl).addClass('voted').attr('disabled', true);
}
}, ['error', 'message', 'voted_count']);
}
성능 최적화¶
댓글 페이징¶
// 댓글 페이지 로드
function loadCommentPage(page) {
var params = {
document_srl: window.document_srl,
cpage: page
};
jQuery('#comment-list').addClass('loading');
exec_xml('board', 'getBoardCommentPage', params, function(ret) {
jQuery('#comment-list').removeClass('loading').html(ret.html);
// 스크롤 위치 조정
scrollToComments();
});
}
댓글 템플릿 캐싱¶
// 템플릿 캐싱
var commentTemplate = null;
function getCommentTemplate() {
if(!commentTemplate) {
commentTemplate = jQuery('#comment-template').html();
}
return commentTemplate;
}
// 템플릿을 사용한 댓글 렌더링
function renderComment(comment_data) {
var template = getCommentTemplate();
return template.replace(/\{([^}]+)\}/g, function(match, key) {
return comment_data[key] || '';
});
}
모범 사례¶
- 에러 처리: 모든 AJAX 요청에 적절한 에러 처리
- 로딩 표시: 사용자에게 진행 상황 표시
- 중복 방지: 요청 중 버튼 비활성화
- 접근성: 키보드 네비게이션 지원
- 모바일 최적화: 터치 이벤트 고려
다음 단계¶
AJAX 댓글 시스템을 구현했다면, 리스트 고급 기능을 학습하세요.