Vanilla JS로 댓글 기능이 있는 게시판 만들기_1일차
📚 프로젝트 주제와 목표
Vanilla JS만 사용하여 댓글 기능이 있는 게시판을 만드는 과제를 하게 되었다. 솔직히 걱정은 좀 됐지만 안될때 조금씩 참고해보라고 원본 소스파일을 주시기도 했고 구글링도 있으니까 일단 해보기나 하자는 생각이다. 목표는 최대한 원본 소스를 참고하지 않고 기능을 똑같이 구현해보는 것이다.
💻 필요한 기능
이 프로젝트(라기엔 많이 사소하지만 어쨌든)에 필요한 기능은 아래와 같다.
- 순수 자바스크립트(Vanilla JS)로 작업할것
글쓰기 버튼을 누르면 상단의 글 목록에 작성한 게시글이 등록된다.
2-1. 작성자, 제목, 내용 중 하나라도 빈 값이 있다면 게시글을 등록하지 않고 오류 메시지를 띄운다.(유효성 체크)
2-2. 게시글 등록시 기존글보다 최신글이 상위에 등록된다.(최신글 순 정렬)
- 글 목록의 게시글을 누르면 댓글 작성 및 댓글 목록 영역이 SlideDown 효과와 함께 나타나고 다시 누르면 SlideUP 효과와 함께 사라진다. (애니메이션, 토글)
- 댓글 작성 영역의 등록 버튼을 누르면 작성한 댓글이 하단의 댓글 목록 영역에 등록된다.
4-1. 댓글 작성자, 댓글 내용 중 하나라도 빈 값이 있다면 댓글을 등록하지 않고 오류 메시지를 띄운다.(유효성 체크)
4-2. 댓글이 등록될 경우, 게시글 제목 영역에 해당 게시글에 있는 댓글의 개수가 표시된다.
4-3. 댓글이 여러개 등록될 경우, 댓글 개수표시 영역에 카운트가 추가된다.
🧱 1일차 구현 내용
이 4가지 기능 중 1일차에 구현한 내용은 아래와 같다.
게시판 전체 HTML 구조 마크업 및 CSS 작성
- 글쓰기 버튼 클릭시 작성자, 제목, 내용 중 빈 값이 있는지 유효성 체크하여 alert창 띄우고 빈 값이 있는 input에 focus 주기
- 게시글 등록시에 나타나는 날짜 및 시간 추가
- 게시글 최신순으로 등록되게 하기
게시판 HTML 구조 마크업 & CSS
HTML
<div class="list-box">
<ul id="list">
<li>
<div>
<p class="title">게시글 제목<span class="reply-count">[4]</span></p>
<p class="user-info fs-12 txt-gray">작성자 | 2022-08-02 9:15:69</p>
</div>
<div>
<p class="content">게시글 본문 내용</p>
</div>
<div class="reply-box fs-12">
<div class="reply-write">
<input type="text" id="replyUserName" style="width: 18%;">
<input type="text" id="replyContent" style="width: 70%;">
<button id="btnAddReply" class="btn btn--gray">등록</button>
</div>
<div class="reply-list">
<p class="reply">[작성자] 댓글내용 | 2022-08-02 9:15:69</p>
</div>
</div>
</li>
</ul>
</div>
<div class="write-box">
<div>
<label for="userName">작성자</label>
<input type="text" id="userName">
</div>
<div>
<label for="title">제목</label>
<input type="text" id="title">
</div>
<div>
<label for="content">내용</label>
<textarea id="content"></textarea>
</div>
<button id="btnAddTxt" class="btn btn--black">글쓰기</button>
</div>
CSS
* {
margin:0;
padding:0;
font-family:Verdana,sans-serif;
box-sizing:border-box;
}
input[type='text'], textarea {
width: 80%;
border: 1px solid #ccc;
padding: 5px 10px;
}
.btn {
padding: 5px 10px;
color: #fff;
border: none;
outline: none;
display: inline-block;
}
.btn.btn--gray {
background-color: #666;
}
.btn.btn--black {
background-color: #333;
}
.fs-12 {
font-size: 12px;
}
.txt-gray {
color: #aaa;
}
div[class$='-box']:not(.reply-box) {
width: 550px;
text-align: right;
}
.list-box {
background-color: #eee;
border: 0;
}
.list-box .list li > div:not(.reply-box),
.reply-box .reply-write,
.write-box > div {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
text-align: left;
}
.list-box .list li {
padding: 20px 10px;
border-top: 1px solid #ddd;
}
.reply-box {
text-align: left;
}
.write-box div:last-child {
margin-bottom: 0;
}
.list-box .list .title,
.write-box label {
font-weight: bold;
}
.list-box .list .title .reply-count {
color: blue;
margin-left: 10px;
}
.write-box {
border: 1px solid #ddd;
padding: 20px 10px;
}
.write-box label {
width: 20%;
}
.write-box textarea {
height: 100px;
}
우선은 완성되었을때의 모습을 생각하면서 전체적인 구조의 마크업과 css를 입혔다. 받은 원본 소스코드는 <form> 태그로 구조가 잡혀있었는데, 내가 <form> 태그 사용에는 아직 서툴어서 일단은 그래도 익숙한 <ul>과 <div>형태로 만들어보기로 했다.
BEM 사용!
이번에는 버튼의 모양을 표현할때 btn--gray나 btn--black과 같이 BEM을 사용해 클래스 이름을 지어보았다. BEM(Block Element Modifier)은 HTML 클래스 속성의 작명법 중 하나인데, 최근에 강의를 들으면서 사용법을 배웠다. __가 있으면 특정 요소의 일부분임을 표시하는 것이고, --가 있으면 요소의 상태를 표시하는 것이다.
예를 들어 container__name이나 item__name 같은 경우는 container의 이름, item의 이름 즉 특정한 요소의 일부분임을 나타내는 것이고 btn--primary, btn--success, btn--error 과 같은 경우 요소(버튼)가 기본타입인지, 성공했을때인지, 에러가 났을때인지 요소의 상태를 구분해 나타낼 수 있다.
직접 사용해보니 class의 길이가 길어질 수 있다는 것은 단점이지만 이 요소가 어느 요소의 일부분인지 빨리 구분이 된다는 점이 좋았고 버튼의 상태에 따라 class를 주게 되면서 해당 요소의 의미를 빨리 알 수 있다는 점이 좋았다. 내가 생각했을때 BEM방식의 장점은 역시 의미 없는 네이밍이 줄어든다는 점이 아닐까 한다. 공부할때도 일을 할때도 가장 어려운건 역시 네이밍인데 BEM방식을 따르면 좀 더 직관적으로 이름을 지을 수 있을 것 같다.
글쓰기 버튼 클릭 이벤트
작성한 스크립트 전체 코드
const btnAddTxt = document.getElementById('btnAddTxt');
btnAddTxt.addEventListener('click', function(){
const userName = document.getElementById('userName');
const title = document.getElementById('title');
const content = document.getElementById('content');
const list = document.getElementById('list');
const makeLi = document.createElement('li');
let date = new Date();
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
let hour = date.getHours();
let minute = date.getMinutes();
let second = date.getSeconds();
let msecond = date.getMilliseconds();
let fullDateTime = year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + msecond;
let addList = '';
if (userName.value == "") {
alert('작성자를 입력해주세요.');
userName.focus();
} else if (title.value == "") {
alert('제목을 입력해주세요.');
title.focus()
} else if (content.value == "") {
alert('내용을 입력해주세요.');
content.focus();
} else {
addList = '<div>'
+ '<p class="title">' + title.value + '<span class="reply-count"></span></p>'
+ '<p class="user-info fs-12 txt-gray">' + userName.value + ' | ' + fullDateTime +'</p>'
+ '</div>'
+ '<div>'
+ '<p class="content">'+ content.value +'</p>'
+ '</div>'
+ '<div class="reply-box fs-12">'
+ '<div class="reply-write">'
+ '<input type="text" name="replyUserName" style="width: 18%;">'
+ '<input type="text" name="replyContent" style="width: 70%;">'
+ '<button name="btnAddReply" class="btn btn--gray">등록</button>'
+ '</div>'
+ '<div class="reply-list"></div>'
+ '</div>';
makeLi.innerHTML = addList;
list.prepend(makeLi);
}
게시글 등록시 나타나는 날짜 및 시간
게시글에 나타나야하는 날짜와 시간의 형태는 다음과 같고 사용한 변수는 아래와 같이 만들었다.
연도네자리-월-일 시:분:밀리초
let date = new Date();
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
let hour = date.getHours();
let minute = date.getMinutes();
let second = date.getSeconds();
let msecond = date.getMilliseconds();
let fullDateTime = year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + msecond;
✍ Check
- new Date() : 생성자로 호출하여 새로운 Date 객체를 반환
- .getFullYear() : 현지 시간 기준 연도(네 자리 연도면 네 자리로)를 반환
- .getMonth() : 현지 시간 기준 월(0–11)을 반환
.getDate() : 현지 시간 기준 일(1–31)을 반환
- .getHours() : 현지 시간 기준 시(0–23)를 반환
- .getMinutes() : 현지 시간 기준 분(0–59)을 반환
- .getSeconds() : 현지 시간 기준 초(0–59)를 반환
- .getMilliseconds() : 현지 시간 기준 밀리초(0–999)를 반환
.getMonth()의 경우 0부터 시작하기때문에 + 1을 해주어 1부터 숫자가 나오도록 했다. 변수 fullDateTime에는 작성해야하는 형식에 맞추어서 변수와 문자열을 이어 작성해두었다. 나중에 이 형식이 필요한 자리에 해당 변수만 선언하면 작성한 형식대로 데이터가 출력될 것이다.
유효성 체크
if (userName.value == "") {
alert('작성자를 입력해주세요.');
userName.focus();
} else if (title.value == "") {
alert('제목을 입력해주세요.');
title.focus()
} else if (content.value == "") {
alert('내용을 입력해주세요.');
content.focus();
} else {
addList = '<div>'
+ '<p class="title">' + title.value + '<span class="reply-count"></span></p>'
+ '<p class="user-info fs-12 txt-gray">' + userName.value + ' | ' + fullDateTime +'</p>'
+ '</div>'
+ '<div>'
+ '<p class="content">'+ content.value +'</p>'
+ '</div>'
+ '<div class="reply-box fs-12">'
+ '<div class="reply-write">'
+ '<input type="text" name="replyUserName" style="width: 18%;">'
+ '<input type="text" name="replyContent" style="width: 70%;">'
+ '<button name="btnAddReply" class="btn btn--gray">등록</button>'
+ '</div>'
+ '<div class="reply-list"></div>'
+ '</div>';
makeLi.innerHTML = addList;
list.prepend(makeLi);
}
✍ Check
.value : value 값 가져오기
- .focus() : 해당 요소에 포커싱
유효성 체크의 조건부분은 원본소스를 약간 참고했다. if문으로 작성자의 value가 빈값일때, 제목의 value가 빈값일때, 내용의 value가 빈값일때, 그외(작성자, 제목, 내용의 value 모두 빈값이 아닐때)로 나누어 실행될 코드를 작성했다. 원본소스에는 console.log()를 통해 콘솔에 값을 찍게 되어있는데, 나는 콘솔보다는 alert창이 뜨는게 확인하기 좀 더 쉽다고 생각해서 이렇게 코드를 작성했다. 그리고 만약 이 게시판이 실제로 서비스 된다면 오류가 있다는 메시지가 사라지고 해당하는 부분으로 focus를 주는게 사용하기 더 편할거라고 생각해 코드를 넣었다.
작성자와 제목, 내용 모두 빈칸이 아니라면 addList에 추가되어 나타날 HTML 구조를 문자열 형태로 넣어준다. 중간에 title.value등 변수가 있기때문에 문자열과 변수를 +로 연결해주었다.
게시글 최신순으로 등록되게 하기
makeLi.innerHTML = addList;
list.prepend(makeLi);
✍ Check
- .innerHTML : 요소(element) 내에 포함 된 HTML 또는 XML 마크업을 가져오거나 설정
- .prepend() : 콘텐츠를 선택한 요소 내부의 시작부분에서 삽입
addList의 내용을 li 태그를 생성하는 makeLi에 .innerHTML로 넣어 안에 있던 HTML구조가 문자열 형태가 아니라 HTML마크업으로 가져올 수 있도록 했다. 그리고 게시글을 나중에 등록된순(최신순)으로 나타내기 위해 prepend() 메소드를 사용해 list 내부에 li들이 최신순으로 삽입되게 했다.
⬆ 1일차인 어제 구현한 부분 ⬆
사실 이건 며칠전에 공부한 내용인데 정리하다보니 글작성이 늦어졌다. 다음부턴 좀더 빨리 정리해야지..🙄
'study > JavaScript' 카테고리의 다른 글
[자바스크립트 딥다이브] 04. 변수 (0) | 2022.12.10 |
---|---|
Vanilla JS로 댓글 기능이 있는 게시판 만들기_3일차 (0) | 2022.12.08 |
Vanilla JS로 댓글 기능이 있는 게시판 만들기_2일차 (0) | 2022.12.08 |
Javascript 스터디(1주차) (1) | 2022.12.08 |
숫자 카운트 애니메이션 (0) | 2022.12.08 |