[LWID] westagram 구현

Mustache 🥸·2021년 5월 29일
0

wecode

목록 보기
5/8

개요

지난주에 2주차 세션 및 과제로 Instagram을 클론하는 것을 했다.
이건 TID에는 넣을 수 없어서 Last Week I Did라고 칭하겠다. 너무 어거지인가??? 😛
미션은 총 9가지로 나뉘었는데 아래와 같다.

  1. 로그인 페이지 레이아웃
  2. id, pw 입력 시 로그인 버튼 활성화 기능
  3. 메인 페이지 레이아웃
  4. 댓글 내용 입력 후 Enter나 게시 버튼 누르면 댓글이 추가되는 기능
    여기까지가 필수 과제
  5. ID와 암호 검증
  6. 댓글 좋아요 / 삭제 기능
  7. 아이디 검색 기능
  8. nav 프로필 사진 클릭 시 메뉴 박스 생성
  9. 반응형 구현
    여기까지가 권장 과제이다.

과제 구현 내역

레이아웃은 html과 CS이기 때문에 넘기고 JS 관련된 것만 정리해보도록 하겠다.

id, pw 입력시 로그인 버튼 활성화

이 과제는 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인지를 식별하여 함수를 실행하게 된다.

댓글 내용 입력 후 enter나 게시 버튼 누르면 댓글 추가

처음 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와 암호 검증

여기서부터는 추가 구현과제라 위에서 한 과제에 덮어씌우는 경우가 있었다.
여긴 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주차부턴 리액트가 들어갔고 그에 대해 또 글을 올려야겠다.

0개의 댓글