지난주에 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주차부턴 리액트가 들어갔고 그에 대해 또 글을 올려야겠다.