[Project] instagram clone coding

kingth·2020년 11월 28일
3

Project

목록 보기
1/5
post-thumbnail

우선 내가 클론한 인스타그램 결과물이다. 100% 똑같이 만들진 않았고 최대한 비슷하게 만들어 보려고 노력했다.

실제 인스타 그램 ID가 노출된 제 친구들과 위코드 15기 박채훈님.ㅋㅋㅋ 채훈님이 본인 블로그에 제 실명 언급하셨대서 저도 언급합니다.ㅋㅋㅋㅋㅋㅋ 애쉬아일랜드 님은 그냥 팬심ㅋㅋㅋ
제글을 보시는 분들은 많은 팔로우 부탁드립니다^^

서론이 길었네요...

많은 기능을 구현한건 아니지만 내가 구현한 기능들을 나열해보자면

  1. id/pw 입력 값 검증(validation) - login.js
  2. 로그인 창 왼쪽의 휴대폰 화면 슬라이드 -login.js
  3. 댓글 달기 - main.js
  4. 댓글 삭제 / 좋아요 버튼 - main.js
  5. 유저 검색 기능 - main.js
  6. nav바 프로필 사진 클릭시 메뉴바 노출 - main.js

구현한 기능들을 상세히 훑어 보겠다.

1. id/pw 입력값 검증

const id = "test@test.com";
const pw = "12345";

const checkRealtimeValue = () => {
  const emailValue = document.querySelectorAll("input")[0].value;
  const pwValue = document.querySelectorAll("input")[1].value;
  const disabledFalse = () => {
    $button.classList.add("activate-button");
    $button.disabled = false;
  };
  const disabledTrue = () => {
    $button.classList.remove("activate-button");
    $button.disabled = true;
  };

  emailValue.includes("@") && pwValue.length >= 5
    ? disabledFalse()
    : disabledTrue();
};

해당 기능을 구현할때 삼항연산자를 이용했다.

Javascript 공부를 하면서 자주 사용해보지 못한 문법이라 조금 버벅이긴 했지만 나름 잘 이해한거 같아 뿌듯했다.

2. 휴대폰 화면 이미지 슬라이드

인스타그램 로그인 페이지를 보면 왼쪽의 휴대폰 그림속 이미지가 계속 변한다.

이걸 구현해 보고 싶어서 추가한 기능이다.

const slide = setInterval(() => {
  const lastImageIndex = $slideImage.length - 1;
  if (imageNumber < lastImageIndex) {
    $slideImage[imageNumber].classList.remove("visible");
    $slideImage[imageNumber + 1].classList.add("visible");
    imageNumber++;
  } else {
    $slideImage[imageNumber - lastImageIndex].classList.add("visible");
    $slideImage[imageNumber].classList.remove("visible");
    imageNumber = 0;
  }
}, 2500);

크게 구현하기 어려운 로직이 필요한건 아니었고,

setInterval() 을 사용해볼 좋은 기회였다.

3. 피드 게시글에 댓글 달기

const postComment = () => {
  const nickname = "kingth_man";
  const inputValue = document.querySelector(".comment-input").value;
  const commentTemplete = `<a href="#" class="comment-list-nickname">${nickname}</a>
    <span>${inputValue}</span>
    <button class="delete-button">...</button>
    <i class="far fa-heart like-button"></i>`;
  const $commentElement = document.createElement("li");

  $commentElement.innerHTML = commentTemplete;
  document.querySelectorAll("ul")[1].appendChild($commentElement);
  document.querySelector(".comment-input").value = "";
  $inputButton.classList.remove("activate-button");
  $inputButton.disabled = true;
};

commentInput.addEventListener("keyup", (event) => {
  const inputValue = document.querySelector(".comment-input").value;
  if (inputValue && event.key === "Enter") postComment();
});

여기서 오늘의 깨달음innerHTML 을 이용하면 태그별 변수를 선언하지 않아도 된다는 것이였다.(하... 이걸 이제 알았네??)

Template literals를 이용해 변수를 받아올수도 있었다.

하면서 댓글이 두개씩 추가되는 버그가 발생했었는데, Enter키 입력으로 댓글을 추가하는 기능을 구현하고 나니 발생한 것이었다.

if (event.key === "Enter") postComment(); 기존의 코드에서는 Enter키 입력 시 댓글 추가 기능에 InputValue

확인하지 않으니 빈칸일때에도 댓글이 추가되는 것이었다. (오늘의 깨달음 추가!)

4. 댓글 삭제 / 좋아요 버튼

const $ulDiv = document.querySelectorAll("ul")[1];

$ulDiv.addEventListener("click", (event) => {
  if (event.target.tagName === "I") {
    if (!event.target.classList.contains("fas")) {
      event.target.classList.add("fas");
      event.target.style.color = "#ED4956";
    } else {
      event.target.classList.remove("fas");
      event.target.style.color = "black";
    }
  }
  if (event.target.tagName === "BUTTON") {
    if (confirm("정말 삭제 하시겠습니까?")) {
      event.target.parentNode.remove();
    }
  }
});

댓글 div를 설계할때,

<ul> 은 모든 댓글의 부모 태그, 하위의 <li> 속에 댓글의 내용이 담기고 삭제 버튼/ 좋아요 버튼을 담아주었다.

event발생시 그 이벤트의 태그네임값을 이용해 각 버튼이 어떤 버튼인지 확인하고 삭제버튼이면 삭제 로직

좋아요 버튼이면 좋아요 로직 으로 구현해 보았다.

5. 유저 검색 기능

가장 긴 로직이 나오는 군요..

const users = [
  {
    id: 'wiinnerb',
    imageUrl: './img/friends1.jpg',
  },
  {
    id: 'joooniboy',
    imageUrl: './img/friends2.jpg',
  },
  {
    id: 'kingth_man',
    imageUrl: './img/my_profile.jpg',
  },
  {
    id: 'chaehoon.p',
    imageUrl: './img/friends3.jpg',
  },
];

const selectUSer = () => {
  const $searchViewList = document.querySelectorAll(".search-list-flex");
  $searchViewList.forEach((element) => {
    document.querySelector(".search-list-ul").removeChild(element);
  });
  const inputValue = document.querySelector(".search-input").value;
  const searchUsers = users.filter((user) => {
    return user.id.indexOf(inputValue) !== -1;
  });

  if (inputValue) {
    searchUsers.forEach((searchUser) => {
      if (searchUser)
        document.querySelector(".search-list").classList.remove("hidden");
      addElement(searchUser.id, searchUser.imageUrl);
    });
  } else document.querySelector(".search-list").classList.add("hidden");

  function addElement(id, imageUrl) {
    const selectViewTemplete = `<div><img src=${imageUrl} alt="" /></div>
    <div>${id}</div>`;
    const $selectViewElement = document.createElement("li");
    $selectViewElement.innerHTML = selectViewTemplete;
    $selectViewElement.classList.add("search-list-flex");
    document.querySelector(".search-list-ul").appendChild($selectViewElement);
  }
};

현재는 최소한의 기능들만 구현하고 있어서 user 배열을 보면 유저 정보가 많이 들어있진 않다.

추후에 하게 될 일로 내가 생각한 것은 결국 서버로 부터 userAPI를 받아와서 필요한 정보를 뽑아 쓰는것이라고 생각했다.

사실 이제 웹 개발에 입문하게 되었고 현업에는 어떻게 사용하는지 몰도라 눈치껏 알아차린 정보라서 확실한 정보는 아닐지 몰라도,

어쨌든 javascript라는 언어에서는 객체를 얼마나 잘 다루냐가 중요하다고 생각한다.

그래서 users라는 배열의 각 값은 한 유저의 { id, 프로필 사진 } 이 담긴 객체이다.

우선 searchUsersusers.filter() 를 이용해

inputValueuser.id에 포함되어있는 { id, imageUrl }형태의 값을 가지는 새로운 배열로 반환한다.

(즉, searchUsersusers에서 검색창에 입력한 값이 id에 포함된 유저객체 만을 가진 새로운 배열. 검색 결과라는 말이다.)

검색 결과가 나왔으니 그 결과들로 addElement(id, imageUrl) 를 실행 시켜준 것이다.

검색 결과가 여러 유저가 있을테니 forEach를 사용했다.

6. nav바 프로필 사진 클릭시 메뉴바 노출(모달창)

nav바에 프로필 사진을 클릭하면 하위 메뉴를 보이게 하는 기능이다.

그리고 다른 곳을 클릭하면 메뉴가 닫히도록 구현.

const $html = document.querySelector("html");

$html.addEventListener("click", (event) => {
  if (event.target.classList.contains("profile-button")) {
    document.querySelector(".menu-box").classList.remove("hidden");
    document.querySelector(".menu-box").classList.add("show-menu-box");
  } else {
    document.querySelector(".menu-box").classList.add("hidden");
    document.querySelector(".menu-box").classList.remove("show-menu-box");
  }
});

const $html = document.querySelector("html"); 이벤트 핸들러를 $html 에 추가했다.

아마 이게 이 문제의 핵심이지 않을까 싶다. 화면 어느곳을 클릭하던 해당 로직이 구현되어야 한다.

근데 그 이벤트가 발생한 타겟이 프로필 사진 일때만 보이게 하면 된다.

이걸 구현하면서 생긴 궁금증인데 지금까지는 필요한 요소를 선택해서 이벤트 핸들러를 추가했는데

html 전체에 이벤트별 핸들러를 구성하고 그 안에서 또 타겟별 로직을 짜면 코드가 간결해 지지 않을까?

const $html = document.querySelector("html");

$html.addEventListener("click", (event) => {
  if(event.target.classList.contains("apple")) apple();
  if(event.target.classList.contains("banana")) banana();
});

$html.addEventListener("keyup", (event) => {
  if(event.target.classList.contains("max")) max();
  if(event.target.classList.contains("min")) min();
});

이런식으로 말이다.

멘토님들한테 물어봐야겠다.

혹시나 제 지나가다 들르신 선배 개발자님들이 계신다면 댓글로 답변해주셔도 너무 감사하겠습니다.

아니라면 미래의 내가 공부해와서 내용을 추가하자! 😎

profile
왜?를 생각하며 개발하기, 다양한 프로젝트를 경험하는 것 또한 중요하지만 내가 사용하는 기술이 어떤 배경과 이유에서 만들어진 건지, 코드를 작성할 때에도 이게 최선의 방법인지를 끊임없이 질문하고 고민하자. 이 과정은 앞으로 개발자로 커리어를 쌓아 나갈 때 중요한 발판이 될 것이다.

0개의 댓글