Instagram Clone Coding 1 : JavaScript

itssweetrain·2021년 3월 27일
0

project

목록 보기
1/8
post-thumbnail

Youtube 는 UI만 구현해 보았다면 Instagram는 UI + 자바스크립트 기능까지 추가된 clone coding을 해보았다!



💡 주요 구현 사항

  • 로그인 페이지 레이아웃
  • ID, PW 입력시 로그인 버튼 활성화(ID에 @포함,PW 5글자이상)
  • 메인 페이지 레이아웃
  • 댓글 내용 입력후 press 혹은 게시버튼 클릭시 댓글 추가 기능
  • 댓글 좋아요, 삭제기능

💡 중점적으로 생각한 것들

  • 레이아웃 구현에 있어 semantic tag의 적절한 사용
  • class명과 변수 그리고 함수의 직관적인 작명
  • 개발자 도구의 활용
  • scope에 따른 변수의 위치
  • if문 간결하게 쓰기(삼항연자, else없이 if문에서 끝나기)

💡 What I learned

CSS

  • label을 이용해서 placeholder 처럼 보이게 하는 효과

실제 인스타그램 로그인 화면을 보면, 커서를 입력하고 keypress가 일어날 시, placeholder의 글씨가 작아지며 위로 이동하는 것을 볼 수 있다. placeholder 자체를 이동하는 방법이 없기에, label 요소를 이용했다. label은 input과 항상 같이 쓰이는 태그이다. parents 요소인 div 안에input 태그와 label 태그를 감싸주고, label 태그의 text를 input 태그 안으로 옮기는 과정에서 고민했었다.

처음엔 transform:translate 을 이용하였더니 부모 요소인 body를 기준으로 이동하여...뭔가 개념을 잘못잡고 있다는 생각이 들었다

container 인 div 에도 position : relative; 를 주고, 그 자식요소인 lavel 태그에 position : absolute; 를 줘야 한다. position의 absolute 속성은 자동으로 부모 요소를 찾아 적용시키는 줄 알았는데, 부모태그에도 relative 값을 줬어야 했다.

div 태그의 left : 0 을 하면 container의 왼쪽으로 잘 붙는 것을 볼 수 있다. 여기서 left : 10%란 뜻은 '왼쪽으로부터' 부모요소의 10% 만큼 이동한다는 뜻. (현재 위치에서)왼쪽으로 10%가 아니라 (시작 위치의)왼쪽으로부터 10% 이동이란 뜻이다.

  • 두 개의 border 적용하기

스토리에 추가된 avatar들의 border를 보면 그라데이션으로 border가 있고 이미지 사이에 흰색 border가 또 적용된 것을 볼 수 있다. 이 때는, border와 더불어 box-shadow를 이용하여 그림자를 inset 내부로 주어 테두리와 같은 효과를 줄 수 있다.

  • selector의 우선순위

input과 label을 감싸고 있는 div container에 속한 label들에게 처음 화면에 보이는 폰트 사이즈값으로 13px을 주었다.

.id-container label,
.password-container label {
  position: absolute;
  left: 50px;
  bottom: 15px;
  font-size: 13px;
  color: #cecece;
}

그 다음, DOM을 이용하여 keypress 되었을 때 label의 클래스를 추가하여 클래스를 이용하여 위로 이동하며 폰트 사이즈가 작아지게 하려고 했다

.id-label {
  font-size: 3px;
  transform: translateY(-100%);
  transition: all 0.2s ease-in-out;
}

여기서 .id-container class 요소와 label tag 요소가 동시에 적용되어, 더 높은 우선순위를 갖기 때문에 폰트 사이즈가 적용되지 않고 13px로 유지되는 것을 볼 수 있다. (개발자도구를 보면 text-through가 된 것을 볼 수 있다)
그래서 더 우선순위가 높은 id로 바꾸어주고, 자바스크립트에는 className을 추가하는 것이 아닌 setAttribute를 이용하여 id를 추가해주었다.

보충설명

selector의 우선순위로 대충 크게 점수를 매겨보자면,

-inline styling(html의 style 요소로 직접): 1000점
-id: 100점
-class: 10점
-tag: 1점

<p class="p-tag">나는 p태그, class가 있다</p>
p {
  font-size: 30px;
}
.p-tag {
  font-size: 15px;
}

p tag는 1점, p-tag class는 10점이므로 p-tag 의 font-size인 15px이 적용될 것이다.

만약 css에 아래가 추가된다면?

p.p-tag {
  font-size: 100px;
}s

1점(p) + 10점(.p-tag) = 11점 이기 때문에 해당 요소는 100px이 적용될 것이다.

이렇게 하다가...인스타그램과 최대한 똑같이 구현하려는 초기의욕에...라벨이 이동하는 모습이 translate + ease-in-out 의 방법보다 scale로 크기가 줄어들며 이동하는 것이 더 맞다고 생각하여 다시 바꾸었다.

scale을 쓰는 것과 다른 시각적인 효과를 준다!!
translate 을 두 개 이상 쓰려면, transform 각각 주는 것이 아니라 일렬로 작성하면 된다.

.id-label {
  transform: scale(0.8) translate(-20px, -10px);
  transition: 0.1s ease-in-out;
}

JavaScript

  • event.target

여러 인자에 동시에 addEventListener 추가하기
각각의 event listener 를 각각의 button에 추가하는 것보다, 하나의 event listener를 만들어 div 태그에 추가하고 event.target 요소를 이용하는 것이 효율적이다.

각각의 댓글에 달에 삭제 버튼과 좋아요 버튼을 클릭하면 똑같이 기능 구현이 되게, event.target 개념을 써보자
또한 element.closest 메소드를 써서 댓글이 div가 li에 버튼 2개와 입력 text가 들어갈 span을 감싸게 코드를 짰는데, 부모요소인 div를 찾아 삭제해주니 깔끔하게 적용된 것을 볼 수 있다

자기 자신을 포함하여 CSS 선택자와 일치하는 가장 가까운 조상 요소를 찾을 수 있게 도와준다.

closest메서드는 해당 요소부터 시작해 DOM 트리를 한 단계씩 거슬러 올라가면서 원하는 요소를 찾는다. CSS 선택자와 일치하는 요소를 찾으면, 검색을 중단하고 해당 요소를 반환한다.

closest.method의 예시

<h1>목차</h1>
<div class="contents"> 
	<ul class="book"> 
		<li class="chapter">1</li>
		<li class="chapter">2</li>
	</ul>
</div> 

<script> 
	let chapter = document.querySelector('.chapter'); // LI 
alert(chapter.closest('.book')); // UL 
alert(chapter.closest('.contents')); // DIV
alert(chapter.closest('h1')); // null(h1은 li의 조상 요소가 아님)

event.target의 예시

<div id="area">
  <button type="button" class="btn" id="btn1">Play With Me!</button>
  <button type="button" class="btn" id="btn2">Play With Me!</button>
</div>
document.getElementById('area').addEventListener('click', e => {
  changeColor(e.target);
});

function changeColor(element) {
  element.style.backgroundColor = "blue";
}

이 둘을 적용한 나의 code✍️

delBtn.addEventListener('click', event => {
    event.target.closest('li').remove();
    })

likeBtn.addEventListener('click', event => {
    event.target.closest('button').innerHTML = `<svg aria-label="좋아요 취소" class="_8-yf5 " fill="#ed4956" height="12" viewBox="0 0 48 48" width="12"><path d="M34.6 3.1c-4.5 0-7.9 1.8-</path></svg>(백틱끝)

💡 Refactoring

(passwordBox.value.length >= 5 && idBox.value.includes('@')) ? loginBtn.style.background = '#2f95f6' : loginBtn.style.background = '#b2dffb'
  • 긴 스트링은 변수 box에 다 넣자
    passwordBox.value.length와 같은 경우 식 하나에 바로 넣어줬는데 passwordBox.value를 하나의 변수란 box에 넣어주어 더욱 깔끔하게 만들자. 어떤 건 변수를 따로 만들어주고, 어떤 건 내 마음대로 코드안에 바로 입력하고 통일성도 없어졌다. 긴 스트링을 직접 작성해서 넣을 경우 오타의 가능성 때문에 안전하지 않고 변수에 담아주는 것으로 IDE에서 제공하는 자동완성 기능과 에러 메세지를 통해 좀 더 에러의 가능성에서 안전해진다!

  • 인라인 스타일링 지양
    삼항연자안에 loginBtn.style.backgroundColoc = "#000000" 이렇게 바로 넣어줬는데 이러한 인라인 스타일링은 HTML 마크업과 CSS 스타일링이 구분되지 않도록 해 유지보수가 어려워진다. 클래스를 부여하여 스타일링 하는 방식으로 리팩토링을 하였다

Refactoring ✍️

.currentColor {
  background-color: "#b2dffb";
}

.changeColor {
  background-color: "#2f95f6";
}

Refactoring ✍️

const passwordValue = passwordBox.value;
const idValue = idBox.value;

(passwordValue.length >= 5 && idValue.includes('@')) ? loginBtn.classList.add('') : loginBtn.classList.add('');

  • 변하지 않는 고정값인 상수는 변수할당할 때 대문자로 작성
const labelMoving = 'label-moving';
const inputPadding = 'input-padding';

Refactoring ✍️

const LABEL_MOVING = 'label-moving';
const INPUT_PADDING = 'input-padding';
  • bold 보다는 strong이 SE에 더 좋다
const fixedMyId = "itssweetrain";
const makeIdBold = fixedMyId.bold();

Refactoring ✍️

span.innerHTML = `<strong>${fixedMyId}</strong> ${text}`;

💡 What should I learn

메인페이지 레이아웃을 전체적으로 구현하는데 시간이 많이 걸렸던 것 같다. 이 부분은 더욱 많이 만들어보고 자꾸 구조를 생각해보는 습관을 가지면 익숙해질 것같다. 머릿속으로 생각하지 말고 직접 그려보기도 하고 어떤 semantic tag를 효과적으로 쓸 수 있는지도 목록을 쭉 적어보며 구체화하자. css에는 답이 없다. 하지만 최대한 효율적이고 간결하게 짜려는 연습과 여러가지 케이스를 많이 공부해야겠다는 생각이 많이 들었다.

특히, position 부분은 배열이 깨지지 않도록 어떤 것을 써야 언제 어디서든 페이지를 열고 줄였을 때 원하는 모습대로 나올까 더 많은 고민과 적용을 해봐야한다. position 관련 글만 세개는 쓴 거 같은데 아직도 확신의! 코드가 쓰여지지 않는다.

변수를 함수 밖에서 선언하는지, 함수 안에서 선언하는지에 따라서 기능이 작동하기도, 안하기도 한다. 이것에 관련하여 변수 & scope 에 대한 글도 따로 작성해두었는데, 곱씹어 볼수록 정말 중요한 개념이라고 생각하게 되었고 더욱 변수의 위치에 유의해서 작성하도록 해야겠다.

profile
motivation⚡️

1개의 댓글