[ 코드잇 스프린트 ] 교육기간 5일차 TIL

2024. 11. 14. 09:14·교육/코드잇 스프린트 : 단기심화 5기


강의 목표

강의시간에 학습한 내용을 정리합니다.

 

강의 내용 정리

강의시간에 학습한 내용을 정리합니다.

 

 

실습 - 스크롤 링크드 애니메이션

목표

 

https://codesandbox.io/p/sandbox/scrolling-wave-b07dmz?file=%2Fsrc%2FApp.tsx

 

codesandbox.io

 

 

정답코드

import * as React from "react";
// import { useScroll, animated, useSpring } from "@react-spring/web";
import { useScroll, useSpring, useTransform, motion } from "framer-motion";

import styles from "./styles.module.scss";

const PAGE_COUNT = 5;

function ScrollLinked() {
  const { scrollYProgress } = useScroll();
  const clipPath = useTransform(
    scrollYProgress,
    (scrollYProgress) => `circle(${scrollYProgress * 100}%)`
  );
  const y = useSpring(100, { bounce: 0 });
  useTransform(scrollYProgress, (scrollYProgress) => {
    if (scrollYProgress > 0.7) {
      y.set(0);
    } else {
      y.set(100);
    }
  });
  const yPercent = useTransform(y, (y) => `${y}%`);

  return (
    <div className={styles.body}>
      <div className={styles.animated__layers}>
        <motion.div
          className={styles.dot}
          style={{
            clipPath,
          }}
        >
          <h1 className={styles.title}>
            <span>
              <motion.span style={{ y: yPercent }}>Aha!</motion.span>
            </span>
            <span>
              <motion.span style={{ y: yPercent }}>You found me!</motion.span>
            </span>
          </h1>
        </motion.div>
      </div>
      {new Array(PAGE_COUNT).fill(null).map((_, index) => (
        <div className={styles.full__page} key={index} />
      ))}
    </div>
  );
}

export default ScrollLinked;

 

 

웹 브라우저에 데이터를 왜 저장할까?

  • 문제 상황
    • 무언가를 작성하다가 브라우저를 닫은 경우
    • 장바구니에 상품을 넣어놨는데 새로고침하니 없어지는 경우
  • 해결 방법
    • 웹 브라우저에 데이터를 저장하는 방법을 통해 이런 상황을 해결
  • 쿠키
    • 쿠키는 key-value로 구성된 문자열 데이터
    • 브라우저에 저장됨
    • 유저가 로그인한 경우, 해당 유저를 식별할 수 있는 형태로 세팅
    • 아이디 기억하기 기능, 팝업 하루동안 보지 않기 기능 등..

 

쿠키 저장 방법 및 특징

  • 서버를 통해 저장
    • http 응답 헤더에 set-cookie 키 값으로 설정 ( 대소문자 상관없음 )
    • 쿠키는 도메인 별로 구분해서 저장됨
  • 클라이언트 자바스크립트 코드를 통해 저장
    • document.cookie
  • 쿠키 용량 제한
    • 쿠키 하나는 최대 4KB
    • 사이트 하나당 대략 20여개의 쿠키 허용
  • Expires 옵션
    • 지정된 날짜까지 쿠키가 유지됨
    • UTC 형식으로 작성
  • Max-Age 옵션
    • 쿠키가 유지될 기간을 초 단위로 설정
    • Expires 와 Max-Age 가 모두 설정되어 있다면 Max-Age가 우선적용됨

 

쿠키에서 자주 사용되는 옵션

  • 쿠키에는 여러 옵션을 추가할 수 있음
  • 쿠키의 기한과 관련된 옵션
    • Expires, Max-Age
    • 세션 쿠키 : 브라우저가 닫힐 때 삭제됨
      • Expires, Max-Age 옵션으로 변경가능 → 지속 쿠키
  • 쿠키의 보안과 관련된 옵션
    • Domain, Path, Secure, SameSite, HttpOnly
    • Domain 옵션
      • 서로 다른 도메인은 물론이고, 서브 도메인 에서도 메인 도메인 쿠키에 접근 불가 ( domain 옵션이 사용되지 않은 경우 )
      • Domain 옵션을 통해 변경 가능
        • codeit.kr에서 아래와 같이 설정하면 서브도메인에서도 해당쿠키에 접근가능
        • user=codeit; Domain=.codeit.kr
    • Path 옵션
      • Path=/cookies로 설정하면 /cookies 페이지에서만 접근가능
      • 즉, 경로가 다르거나 상위 경로(’/’)에서는 접근 불가
    • Secure 옵션 : Https 프로토콜에서만 쿠키가 전송되도록 설정
    • HttpOnly : JS로는 접근불가
    • SameSite : 같은 도메인 또는 다른 도메인에서 접근가능하도록 설정

 

자바스크립트로 쿠키 변경하기

  • 쿠키 추가하기
    • document.cookie = ‘language=korean’;
    • JS의 보통 문법과는 다르게 새로운 값이 할당되는 것이 아니라 새로운 쿠키가 추가됨
  • 쿠키 수정하기
    • document.cookie = ‘language=english’;
    • 수정하려는 쿠키 ‘KEY = VALUE 형태로 저장
  • 쿠키에 특수문자 사용하기
    • 띄어쓰기, 세미콜론 등
    • encodeURIComponent() 사용하기
    • 인코딩된 쿠키를 다시 읽을 때는 decodeURIComponent() 사용하기
    • 옵션된 부분은 인코딩하지 않도록 유의
  • 쿠키 삭제하기
    • Expires 옵션을 이용해 삭제하려는 쿠키에 지난 날짜를 세팅하기
    • 또는 Max-Age 옵션의 값을 0이나 음수로 설정

 

실습 - 쿠기를 다루는 함수 만들기

  • 팝업을 하루 동안 보지 않기 기능을 구현
  • '하루동안 다시 보지 않기' 옵션을 체크하고 팝업창을 닫으면 새로고침을 하거나 사이트에 다시 접속하더라도 하루(24시간)동안은 팝업이 뜨지 않도록
  • 만약 팝업이 뜨지 않는다면 크롬 우측 상단의 '팝업 차단됨'을 클릭해서 항상 허용으로 변경
  • 다음 링크에서 작업하기

정답 코드

cookie-helper.js

function isCookieExist(name) {
  // 쿠키의 이름을 받아서 해당 쿠키가 있으면 true,
  // 없으면 false를 리턴합니다.
  const encodedName = encodeURIComponent(name);
  return document.cookie
    .split("; ")
    .find((cookie) => cookie.startsWith(encodedName))
    ? true
    : false;
}

function setCookieWithOptions(name, value, options = {}) {
  // 쿠키의 이름, 값, 옵션을 받아서
  // 쿠키를 추가해주는 함수를 만들어 주세요.
  let cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value);

  if (options.expires instanceof Date) {
    options.expires = options.expires.toUTCString();
  }

  for (let optionKey in options) {
    let optionValue = options[optionKey];
    if (!optionValue) continue;

    cookie += "; " + optionKey;
    cookie += optionValue !== true ? "=" + optionValue : "";
  }

  document.cookie = cookie;
}

function deleteCookie(name) {
  // 쿠키의 이름을 받아서 해당 쿠키를 삭제하는
  // 함수를 만들어 주세요.
  document.cookie = encodeURIComponent(name) + "=; max-age=-1";
}

 

 

popup.js

function setEventListeners() {
  const noPopupCheckbox = document.querySelector("#no-popup-checkbox");
  noPopupCheckbox.addEventListener("change", (e) => {
    if (e.target.checked) {
      const tomorrow = new Date();
      tomorrow.setDate(tomorrow.getDate() + 1);
      // 팝업 하루동안 보지 않기 옵션이 체크된 경우
      // 해당 내용을 저장하는 쿠키를 만들어 추가합니다.
      // 하루가 지나면 쿠키가 삭제되도록 해 주세요.
      console.log("popup.js document.cookie" + document.cookie);
      setCookieWithOptions("no-popup", true, {
        expires: tomorrow,
      });
    } else {
      // 팝업 하루동안 보지 않기 옵션을 체크 해제한 경우
      // 위에서 저장했던 쿠키를 삭제해 주세요.
      console.log("popup.js document.cookie" + document.cookie);
      deleteCookie("no-popup");
    }
  });
}

setEventListeners();

 

 

script.js

function showPopUp() {
  window.open("popup.html", "popup", "width=300, height=150");
}

window.onload = () => {
  // 팝업에서 저장했던 쿠키가 존재하는 경우
  // 팝업을 보여 주지 않도록 해 주세요.
  if (!isCookieExist("no-popup")) {
    showPopUp();
  }
};

 

 

 

웹 스토리지

  • 웹 스토리지란?
    • 로컬 스토리지와 세션 스토리지
    • 둘다 key-value 형태로 데이터를 저장함
  • 로컬 스토리지
    • 인터넷 댓글 창이나 메신저 창에 적고 아직 전송하지 않은 메시지
  • JS로 웹 스토리지 객체 접근하기
    • window.localStorage ( “ window. “는 생략가능 )
    • window.sessionStorage

 

웹 스토리지 vs 쿠키

  웹 스토리지 쿠키
기한 로컬 : 영구
세션 : 탭 열려있는 동안만 유지
한정
동작 기본 동작 없음 http 요청에 자동 전송
저장 용량 큼 작음
설정 방법 JS only JS + http 응답 헤더

 

 

세션 스토리지

  • 브라우저 탭별로 생성
  • 탭이 열려 있는 동안만 유지
  • 페이지를 새로고침해도 유지

 

웹 스토리지

  • 웹 스토리지가 저장되는 기준
    • origin 기준 ( = 스키마(프로토콜) + 도메인(호스트네임) + 포트 )
  • 로컬 스토리지 사용 예
    • 입력창 메시지 저장
    • 사용자 설정
    • 테마
    • 오프라인 데이터 등..
  • 세션 스토리지 사용 예
    • 일회성 로그인
    • 브라우저 세션 동안만 유지되는 장바구니 등..
  • 웹스토리지 사용시 주의점
    • JS코드를 통해 탈취 및 조작이 가능
    • 민감한 정보들은 저장 X
  • 웹 스토리지 다루기
    • console창에서 localstorage로 데이터 확인
  • 데이터 추가하기
    • localStorage.setItem( 이름, 값 )
  • 데이터 가져오기
    • localStorage.getItem( 이름, 값 )
    • 로컬 스토리지에 저장될때는 모두 문자열로 저장됨
    • 원래의 자료형으로 쓰고싶다면 타입캐스팅 필요
  • 객체형 데이터 저장하기
    • JSON.strigify( ) 함수로 문자열로 변환해서 저장
    • 문자열로 된 값은 다시 객체로 바꿀땐 JSON.parse( ) 함수 사용
  • 데이터 수정하기
    • setItem( ) 함수로 바꾸고싶은 데이터의 키에 새로운 값을 넣기
  • 데이터 삭제하기
    • 모든 데이터 삭제를 원한다면 localStorage.clear( ) 함수 사용
  • 세션스토리지 데이터 사용법도 동일함
    • sessionStorage.setItem ( ‘language’ , ‘korean’ )
    • sessionStorage.getItem( ‘language’ )
    • sessionStorage.removeItem( ‘language’ )
    • sessionStorage.clear( )

 

실습 - 변경된 색상 값 유지하기

목표

  • 박스의 채우기 색깔과 테두리 색깔 변경, 변경된 값을 계속 유지
  • 다음 링크 에서 작업

 

내 코드

function changeBoxColor(color) {
  const box = document.getElementById('box');
  box.style['background-color'] = color;
}

function changeBoxBorderColor(borderColor) {
  const box = document.getElementById('box');
  box.style['border-color'] = borderColor;
}

function setInitialValues() {
  // 로컬 스토리지에 저장된 값이 있으면 해당 값으로 설정하고, 없다면 기s본 "#ff0000"로 지정합니다.
  const currentBoxColor = localStorage.getItem('boxColor')
    ? localStorage.getItem('boxColor')
    : '#ff0000';

  // 로컬 스토리지에 저장된 값이 있으면 해당 값으로 설정하고, 없다면 기본 "#000000"으로 지정합니다.
  const currentBoxBorderColor = localStorage.getItem('boxBorderColor')
    ? localStorage.getItem('boxBorderColor')
    : '#000000';

  document.getElementById('box-color').value = currentBoxColor;
  document.getElementById('box-border-color').value = currentBoxBorderColor;

  changeBoxColor(currentBoxColor);
  changeBoxBorderColor(currentBoxBorderColor);
}

function setEventListeners() {
  const boxColorSelector = document.querySelector('#box-color');
  boxColorSelector.addEventListener('change', (e) => {
    // 박스 색깔이 바뀌면 로컬 스토리지에 저장된 값을 업데이트해 주세요.
    localStorage.setItem('boxColor', e.target.value);
    changeBoxColor(e.target.value);
    console.log('current boxColor : ', localStorage.getItem('boxColor'));
  });

  const boxBorderColorSelector = document.querySelector('#box-border-color');
  boxBorderColorSelector.addEventListener('change', (e) => {
    // 박스 테두리가 바뀌면 로컬 스토리지에 저장된 값을 업데이트해 주세요.
    localStorage.setItem('boxBorderColor', e.target.value);
    changeBoxBorderColor(e.target.value);
    console.log(
      'current boxBorderColor : ',
      localStorage.getItem('boxBorderColor')
    );
  });
}

setInitialValues();
setEventListeners();

 

 

주요코드

// input태그를 통해 설정된 색상값을 setItem을 통해 저장
localStorage.setItem('boxColor', e.target.value);
localStorage.setItem('boxBorderColor', e.target.value);

// localStograge에 저장된 색상값이 있으면 가져와서 적용하고 없으면 기본값 사용
const currentBoxColor = localStorage.getItem('boxColor')
	? localStorage.getItem('boxColor')
	: '#ff0000';
const currentBoxBorderColor = localStorage.getItem('boxBorderColor')
	? localStorage.getItem('boxBorderColor')
	: '#000000';

 

정답 코드

function changeBoxColor(color) {
  const box = document.getElementById("box");
  box.style["background-color"] = color;
}

function changeBoxBorderColor(borderColor) {
  const box = document.getElementById("box");
  box.style["border"] = "thick solid " + borderColor;
}

function setInitialValues() {
  const currentBoxColor = localStorage.getItem("box-color") ?? "#ff0000";
  const currentBoxBorderColor =
    localStorage.getItem("box-border-color") ?? "#000000";

  document.getElementById("box-color").value = currentBoxColor;
  document.getElementById("box-border-color").value = currentBoxBorderColor;

  changeBoxColor(currentBoxColor);
  changeBoxBorderColor(currentBoxBorderColor);
}

function setEventListeners() {
  const boxColorSelector = document.querySelector("#box-color");
  boxColorSelector.addEventListener("change", (e) => {
    localStorage.setItem("box-color", e.target.value);
    changeBoxColor(e.target.value);
  });

  const boxBorderColorSelector = document.querySelector("#box-border-color");
  boxBorderColorSelector.addEventListener("change", (e) => {
    localStorage.setItem("box-border-color", e.target.value);
    changeBoxBorderColor(e.target.value);
  });
}

setInitialValues();
setEventListeners();

 

 

실습 - 웹 스토리지 실습

목표

  • 세션 스토리지를 활용해서 간단한 장바구니를 구현
  • 아이템을 장바구니에 담으면 장바구니에 있는 아이템 개수 변경
  • '장바구니로 가기' 링크를 클릭하면 현재까지 담은 아이템들의 종류와 개수 표시
  • '주문하기' 버튼을 누르면 주문이 완료되었다는 팝업이 뜨고 다시 메인 화면으로 이동

 

내 코드

index.js

const totalItemCountInCartText = document.querySelector(
  '#total-item-count-in-cart'
);

// 현재 장바구니를 세션 스토리지에서 가져오는 함수
// + 예외 처리 추가
function getCartItems() {
  try {
    const cartItems = sessionStorage.getItem('cartItems');
    return cartItems ? JSON.parse(cartItems) : {};
  } catch (error) {
    console.error('세션 스토리지에서 데이터를 가져오는 중 오류 발생:', error);
    return {};
  }
}

function getTotalItemCount() {
  // 현재 장바구니에 담겨 있는 아이템 목록을 가져와서 아이템들의 총 개수를 계산합니다.
  // 세션스토리지로부터 'cartItems'에 대한 JSON형식의 데이터를 가져와서 문자열 객체로 변환
  // ...없으면, 빈 객체를 할당함
  const cartItems = getCartItems();
  let totalItemCount = 0;
  for (const itemCount of Object.values(cartItems)) {
    totalItemCount += itemCount;
  }
  return totalItemCount;
}

function setInitialValues() {
  totalItemCountInCartText.innerHTML = getTotalItemCount();
}

function handleAddClick(button) {
  const itemName = button.dataset['itemName'];
  const cartItems = getCartItems();
  // 현재 장바구니에 있는 아이템 리스트를 받아 옵니다.

  // 해당 아이템이 이미 장바구니에 있으면 개수 증가, 없으면 새로 추가
  cartItems[itemName] = (cartItems[itemName] || 0) + 1;

  // 세션 스토리지에 업데이트된 장바구니 저장
  sessionStorage.setItem('cartItems', JSON.stringify(cartItems));

  totalItemCountInCartText.innerHTML = getTotalItemCount();
}

function handleCartClick(e) {
  e.preventDefault();
  const totalItemCountInCart = getTotalItemCount();
  window.location.href = totalItemCountInCart
    ? './shopping-cart.html'
    : './empty-shopping-cart.html';
}

function setEventListeners() {
  const addToCartButtons = document.querySelectorAll('.add-to-cart-btn');
  addToCartButtons.forEach((button) => {
    button.addEventListener('click', () => handleAddClick(button));
  });

  const goToShoppingCartLink = document.querySelector('#go-to-shopping-cart');
  goToShoppingCartLink.addEventListener('click', handleCartClick);
}

setInitialValues();
setEventListeners();

 

 

shopping-cart.js

const dictionary = {
  apple: '사과',
  orange: '오렌지',
  banana: '바나나',
};

// 세션 스토리지에서 장바구니 데이터를 가져오는 함수
function getCartItems() {
  const cartItems = sessionStorage.getItem('cartItems');
  return cartItems ? JSON.parse(cartItems) : {};
}

function addItemToList(name, num) {
  const cartItemList = document.getElementById('cart-item-list');
  const item = document.createElement('li');
  item.textContent = dictionary[name] + ': ' + num + '개';
  cartItemList.append(item);
}

function createCartItemList() {
  // 장바구니에 담겨 있는 아이템 리스트를 가져옵니다.
  const cartItems = getCartItems();

  for (const [key, value] of Object.entries(cartItems)) {
    addItemToList(key, value);
  }
}

function setInitialValues() {
  createCartItemList();
}

function setEventListeners() {
  const orderButton = document.querySelector('#order-btn');
  orderButton.addEventListener('click', () => {
    console.log('button clicked');
    alert('주문이 완료되었습니다!');
    // 메인 화면으로 이동하기 전에 세션 스토리지에 저장되어 있는 데이터를 삭제해 주세요.
    sessionStorage.clear();
    window.location.href = './index.html';
  });
}

setInitialValues();
setEventListeners();

 

 

정답 코드

index.js

const totalItemCountInCartText = document.querySelector(
  "#total-item-count-in-cart"
);

function getTotalItemCountInCart() {
  const cartItems = JSON.parse(sessionStorage.getItem("cart-items")) ?? {};
  let totalItemCount = 0;
  for (const itemCount of Object.values(cartItems)) {
    totalItemCount += itemCount;
  }
  return totalItemCount;
}

function setInitialValues() {
  totalItemCountInCartText.innerHTML = getTotalItemCountInCart();
}

function handleAddToCartButtonClick(button) {
  const itemName = button.dataset["itemName"];
  const cartItems = JSON.parse(sessionStorage.getItem("cart-items")) ?? {};
  cartItems[itemName] = (cartItems[itemName] ?? 0) + 1;
  sessionStorage.setItem("cart-items", JSON.stringify(cartItems));

  totalItemCountInCartText.innerHTML = getTotalItemCountInCart();
}

function handleGoToShoppingCartLinkClick(e) {
  e.preventDefault();
  const totalItemCountInCart = getTotalItemCountInCart();

  if (totalItemCountInCart) {
    window.location.href = window.location.href =
      "/session-storage-example-new/shopping-cart.html";
  } else {
    window.location.href =
      "/session-storage-example-new/empty-shopping-cart.html";
  }
}

function setEventListeners() {
  const addToCartButtons = document.querySelectorAll(".add-to-cart-btn");
  addToCartButtons.forEach((button) => {
    button.addEventListener("click", () => handleAddToCartButtonClick(button));
  });

  const goToShoppingCartLink = document.querySelector("#go-to-shopping-cart");
  goToShoppingCartLink.addEventListener("click", handleGoToShoppingCartLinkClick);
}

setInitialValues();
setEventListeners();

 

 

shopping-cart.js

import { dictionary } from "./dictionary.js";

function addItemToList(name, num) {
  const cartItemList = document.getElementById("cart-item-list");
  const item = document.createElement("li");
  item.textContent = dictionary[name] + ": " + num + "개";
  cartItemList.append(item);
}

function createCartItemList() {
  const cartItems = JSON.parse(sessionStorage.getItem("cart-items"));

  for (const [key, value] of Object.entries(cartItems)) {
    addItemToList(key, value);
  }
}

function setInitialValues() {
  createCartItemList();
}

function setEventListeners() {
  const orderButton = document.querySelector("#order-btn");
  orderButton.addEventListener("click", () => {
    alert("주문이 완료되었습니다!");
    sessionStorage.clear();
    window.location.href = "/session-storage-example-new/";
  });
}

setInitialValues();
setEventListeners();

 

반응형
저작자표시 비영리 변경금지 (새창열림)

'교육 > 코드잇 스프린트 : 단기심화 5기' 카테고리의 다른 글

[ 코드잇 스프린트 ] 교육기간 7일차 TIL  (1) 2024.11.16
[ 코드잇 스프린트 ] 교육기간 6일차 TIL  (3) 2024.11.15
[ 코드잇 스프린트 ] 교육기간 4일차 TIL  (3) 2024.11.13
[ 코드잇 스프린트 ] 교육기간 3일차 TIL  (0) 2024.11.12
[ 코드잇 스프린트 ] 교육기간 2일차 TIL  (0) 2024.11.08
'교육/코드잇 스프린트 : 단기심화 5기' 카테고리의 다른 글
  • [ 코드잇 스프린트 ] 교육기간 7일차 TIL
  • [ 코드잇 스프린트 ] 교육기간 6일차 TIL
  • [ 코드잇 스프린트 ] 교육기간 4일차 TIL
  • [ 코드잇 스프린트 ] 교육기간 3일차 TIL
heee1
heee1
FE 개발자를 희망하는 임희원 입니다.
  • heee1
    heee1.blog
    heee1
  • 전체
    오늘
    어제
    • 분류 전체보기 (69)
      • Front-end (1)
        • Javascript (4)
        • Typescript (1)
        • React (0)
        • Next.js (1)
        • Tool (1)
        • Git (1)
        • Prettier (0)
        • Test-Framework (1)
        • Vercel (1)
      • 교육 (28)
        • 항해99 : 웹개발 종합반 18기 (14)
        • 프로젝트 캠프 : React 2기 (5)
        • 코드잇 스프린트 : 단기심화 5기 (9)
      • Algorithm (29)
        • Javascript (24)
        • Python (5)
      • 코드 보관함 (1)
        • 배치스크립트 ( .bat ) (1)
  • 블로그 메뉴

    • 홈
  • 링크

    • github
  • 공지사항

  • 인기 글

  • 태그

    자바스크립트
    스프린트
    모킹
    항해99
    react-spring
    next.js
    백준
    JavaScript
    코드잇
    Python
    node.js
    css animation
    til
    speed insights
    tailwindcss
    티스토리챌린지
    jest
    Baekjoon
    오블완
    테스트 프레임워크
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
heee1
[ 코드잇 스프린트 ] 교육기간 5일차 TIL
상단으로

티스토리툴바