
강의 목표
강의시간에 학습한 내용을 정리합니다.
강의 내용 정리
강의시간에 학습한 내용을 정리합니다.
실습 - 스크롤 링크드 애니메이션
목표
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 |
