지난주에 2주차 세션 및 과제로 Instagram을 클론하는 것을 했다.
이건 TID에는 넣을 수 없어서 Last Week I Did라고 칭하겠다. 너무 어거지인가??? 😛
미션은 총 9가지로 나뉘었는데 아래와 같다.
레이아웃은 html과 CS이기 때문에 넘기고 JS 관련된 것만 정리해보도록 하겠다.
이 과제는 input에 id, pw가 한글자 이상 입력되면 로그인 버튼 색상이 바뀌는 형식의 과제이다.
밑에 ID / 암호 검증 과제를 하면서 기존 내용이 지워졌는데 아래와 코드와 같이 구현을 했었다.
const validateInputLength = (name, e) => {
name === 'id' ? (idValue = e.target.value) : (passwordValue = e.target.value);
if (idValue && passwordValue) {
loginButton.classList.add('active');
loginButton.removeAttribute('disabled');
} else {
loginButton.classList.remove('active');
loginButton.setAttribute('disabled', 'disabled');
}
};
하나의 함수로 하기 위해 name
으로 위 함수를 쓰는 input이 id인지 password인지를 식별하여 함수를 실행하게 된다.
처음 JS를 공부할 때 innerHTML 사용의 지양하는 글들을 워낙 많이봐서 이걸 구현할 때 innerHTML이 아닌 textContent를 주로 사용했다.
const addCommentHandler = (e) => {
comment = e.target.value;
if (e.key === 'Enter' && comment) {
displayComment();
}
};
const displayComment = () => {
if (comment) {
const commentLiTag = document.createElement('li');
const commentId = document.createElement('span');
const commentText = document.createElement('span');
const commentLike = document.createElement('button');
const commentRemove = document.createElement('button');
commentId.textContent = 'xoxoxo_S2';
commentId.classList.add('commentor-id');
commentText.textContent = comment;
commentText.classList.add('comment-content');
commentLike.innerHTML = '<i class="fas fa-heart"></i>';
commentLike.classList.add('comment-like-button');
commentLike.addEventListener('click', (e) => changeLikeButtonColor(e));
commentRemove.textContent = '삭제';
commentRemove.classList.add('comment-remove-button');
commentRemove.addEventListener('click', () => removeComment(commentLiTag));
commentLiTag.appendChild(commentId);
commentLiTag.appendChild(commentText);
commentLiTag.appendChild(commentLike);
commentLiTag.appendChild(commentRemove);
commentList.appendChild(commentLiTag);
comment = '';
inputComment.value = '';
}
};
fontawesome을 사용하는 부분만 innerHTML로 처리하고 하나하나 textContent와 appendChild를 이용해서 처리했는데, 내용이 너무나도 길어진게 단점이다.
좋아요 버튼과 삭제버튼은 생성되는 시점에 addEventListener를 주어줘서 이벤트가 바인딩되게 처리했다.
여기서부터는 추가 구현과제라 위에서 한 과제에 덮어씌우는 경우가 있었다.
여긴 id에 '@' 포함, pw는 5글자 이상이어야 로그인 버튼이 활성화 되는 조건이 있었다.
const validateInputLength = (name, e) => {
name === 'id' ? (idValue = e.target.value) : (passwordValue = e.target.value);
if (idValue && idValue.includes('@') && passwordValue.length >= 5) {
loginButton.classList.add('active');
loginButton.removeAttribute('disabled');
} else {
loginButton.classList.remove('active');
loginButton.setAttribute('disabled', 'disabled');
}
};
위에서 이미 조건문을 만들어놨기 때문에 ID는 if문안에 includes
메서드를 활용해 @가 포함되었는지 확인하고 PW는 가장 간단한 length
를 이용하여 처리를 해주었다.
const changeLikeButtonColor = (e) => {
!e.target.className.includes('active')
? e.target.classList.add('active')
: e.target.classList.remove('active');
};
좋아요는 DB가 없으면 단순히 색상만 바뀌면 되는것이기 때문에, class를 추가하고 삭제하는 toggle의 방식으로 처리를 하였다.
// commentRemove.addEventListener('click', () => removeComment(commentLiTag));
const removeComment = (li) => {
li.remove();
};
삭제는 댓글이 만들어질 때 위와 같이 해당 댓글의 부모 요소가 무엇인지 알수있게 처리해주었기 때문에 remove
를 이용하여 바로 삭제하였다.
const searchID = (value) => {
const inputValue = searchBar.value;
return value.id.indexOf(inputValue) !== -1;
};
searchBar.addEventListener('input', () => {
searchResult.innerHTML = '';
searchResult.style.display = 'none';
searchResultTriangle.style.display = 'none';
if (searchBar.value) {
const filterdId = personalInfo.filter((value) => searchID(value));
if (filterdId) {
filterdId.forEach((value) => {
displaySearchResults(value);
});
}
}
});
이번 과제 중 어떻게 할지 가장 고민을 많이 했던 부분이다.
처음엔 indexOf
가 떠올라서 그걸 이용해서 계속 고민해보다가 위코드에서 제시해준 filter
를 섞어서 구현을 했다.
이건 구현하는 것 자체는 어렵지 않았는데, 여기서 세부적인 미션으로는 저 영역외를 클릭했을 때 메뉴가 사라지는걸 구현했어야했는데, 도무지 생각이 안나는것이다. 처음엔 target의 parentNode를 클릭하면 사라지는 것 까지만 하고 어떻게할까 어떻게할까 하다가 멘토님한테 힌트찬스를 써서 outer click이라는 키워드를 얻고 그에 해당하는 이벤트를 구현하였다.
const displayPersonalMenu = (e) => {
const personalMenu = document.querySelector('.personal-menu');
const personalMenuTriangle = document.querySelector('.personal-menu-triangle');
if (e.target.className !== 'nav-button-profile') {
personalMenuTriangle.style.display = 'none';
personalMenu.style.display = 'none';
} else {
personalMenuTriangle.style.display = 'block';
personalMenu.style.display = 'flex';
}
};
body.addEventListener('click', displayPersonalMenu);
위처럼 body에 이벤트를 주어 프로필 버튼을 클릭하면 개인 메뉴가 나타나고 그 외에는 사라지게 구현을 하였다.
반응형은 레이아웃과 마찬가지로 html, css 위주라 따로 작성은 하지 않겠다.
근데 처음에 이것을 구현할 때 viewport 단위를 사용해보고 싶어서 vmin, vmax를 사용했는데, 내가 개념을 잘못이해하고 있어서 브라우저 크기가 커질때 해당 단위를 쓴 엘리먼트들이 너무 커진것이다..
..나의 인스타그램 상태가..?
그래도 자바스크립트를 어느정도 공부했다고 실전 2주차 과제인데도 불구하고 위코드에서 5일동안 과제 기간을 줬지만 하루만에 다해서 나머지 공부할 시간이 좀 많았던 한주였었다.
3주차부턴 리액트가 들어갔고 그에 대해 또 글을 올려야겠다.