(3) Web data storage - 쿠키 (Cookie) 다루는 함수 만들기

반응형

지금까지는 개발자 도구의 콘솔 창에서 쿠키를 확인하거나 변경하는 작업을 해 보았는데 

특정 쿠키가 있는지 확인하거나,

내가 원하는 쿠키의 값을 가져오거나,

쿠키를 추가/삭제하는 작업 등을 하는 함수를 만들어 두면

필요할 때 편리하게 가져다 쓸 수 있다.


쿠키가 있는지 확인하는 함수

먼저 특정 쿠키가 있는지 확인하는 코드를 작성한다.

function isCookieExist(name) {
    const encodedName = encodeURIComponent(name);
  return document.cookie
    .split('; ')
    .find((cookie) => cookie.startsWith(encodedName))
    ? true
    : false;
}

코드를 하나씩 살펴보면

먼저 document.cookie에 서 다음과 같이 하나의 긴 문자열로 된 쿠키 전체를 가져올 수있는데

etc-image-0

결과를 보면 쿠키는 '; ' 로 구분되어 있는 점을 활용해서

먼저 쿠키 전체를 '; ' 로 split()을 실행하면

다음과 같은 배열을 만들 수 있다.

['user=SeopE', 'location=earth']

여기서 find() 함수로 배열을 차례대로 돌면서

내가 찾고 싶은 쿠키의 이름으로 시작하는 값을 확인하고

값이 있으면 true, 없으면 false를 리턴한다.


쿠키 값을 가져오는 함수

이를 이용해 특정 쿠키의 값을 가져오는 함수도 

다음과 같이 로직을 구현할 수 있다.

function getCookieValue(name) {
    const encodedName = encodeURIComponent(name);
  const cookies = document.cookie.split('; ');
  const targetCookieValue = cookies
    .find((cookie) => cookie.startsWith(encodedName))
    ?.split('=')[1];
  return targetCookieValue ? decodeURIComponent(targetCookieValue) : undefined;
}

쿠키를 찾는 것까지는 동일하고

그 뒤에 '="로 한번 더 split() 함수를 실행하였다.

그러면 찾은 쿠키에 대해서 쿠키의 이름은 배열의 0번 인덱스에 들어가게 되고

값은 1번 인덱스에 들어가게 된다.

만약에 location 이라는 이름의 쿠키를 찾았다면 

다음과 같이 배열을 만들 수 있을 것이다.

(여기서 1번 인덱스에 있는 값을 리턴하는것)

['location', 'earth']

쿠키를 추가하는 함수

이번에는 쿠키를 추가하는 함수를 만들어보자

function setCookie(name, value) {
  document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);
}

document.cookie에 이름과 값을 넣어 주되, 값을 인코딩해 주는 것만 주의하면 된다.

만약 유효 시간 등의 옵션을 추가하고 싶은 경우,

다음과 같이 옵션을 받아서 넣을 수도 있다.

function setCookie(name, value, second) {
  document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value) + '; Max-Age=' + second;
}

혹은 다음과 같이 객체로 여러 옵션들을 한 번에 받아서 넣을 수도 있다.

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 && optionValue !== true)? '=' + optionValue : '';
  }

  document.cookie = cookie;
}

쿠키를 삭제하는 함수

마지막으로 특정 쿠키를 삭제하는 함수를 만들어보자.

다음과 같이 Max-Age 값을 -1로 하면 쉽게 쿠키를 삭제할 수 있다.

function deleteCookie(name) {
  document.cookie = encodeURIComponent(name) + "=; Max-Age=-1";
}

만든 함수 사용해보기

이렇게 만들어본 함수들을 직접 사용해보자.

먼저 쿠키하나 설정해보자

setCookie('language', 'korean');

etc-image-1etc-image-2

위와 같이 쿠키가 제대로 추가되어 있는 것을 확인할 수 있고

 

isCookieExist() 함수를 'language'로 호출하면 다음 과 같이 true로 나오고

없는 쿠키 값을 넣으면 false로 나온다.

console.log(isCookieExist('language'));
console.log(isCookieExist('name'));

etc-image-3

getCookieValue 함수를 이용해 값을 콘솔에 찍어보면

역시 값이 잘 나오는 것을 확인할 수 있다.

console.log(getCookieValue('language'));

etc-image-4

옵션을 넣은 쿠키도 추가해보자면

다음과 같이 Max-Age 옵션을 넣어서 새로운 쿠키를 추가해보자.

setCookieWithOptions('name', 'SeopE', { 'Max-Age': 3600 });

etc-image-5etc-image-6

이렇게 Expries / Max-Age에 옵션이 잘 저장된 것을 확인할 수 있다.

 

마지막으로 쿠키를 삭제해보면

deleteCookie('name');
console.log(document.cookies);

etc-image-7etc-image-8

name이라는 쿠키가 삭제되는 것을 확인할 수 있다.


(번외) 하루 동안 팝업 보지 않기 구현 

▶ HTML 파일

더보기
<!-- index.html  -->

<!DOCTYPE html>
<html>
  <head>
    <title>테스트</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <h2 class="heading">테스트</h2>
    <script src="cookie-helper.js"></script>
    <script src="script.js"></script>
  </body>
</html>
<!-- popup.html  -->

<!DOCTYPE html>
<html>
  <head>
    <title>첫 구매 고객 20% 세일</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link rel="stylesheet" href="style.css">
  </head>
  <body class="full-height">
    <main class="full-height-content">
      <div>
        <h2 class="heading">첫 구매 고객 <span class="accent">20%</span> 세일</h2>
        <p>인기 쿠키를 만나보세요!</p>
      </div>
    </main>
    <footer class="full-height-footer">
      <input type="checkbox" id="no-popup-checkbox">하루동안 다시 보지 않기
    </footer>
    <script src="cookie-helper.js"></script>
    <script src="popup.js"></script>
  </body>
</html>

▶ CSS 파일

더보기
@font-face {
  font-family: 'NanumSquareNeo-Variable';
  src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_11-01@1.0/NanumSquareNeo-Variable.woff2')
    format('woff2');
  font-weight: normal;
  font-style: normal;
}

:root {
  --red: #e46e80;
  --orange: #f18575;
  --yellow: #fbc85b;
  --green: #32b9c1;
  --blue: #5195ee;
  --purple: #8579ef;
  --n000: #f9fafc;
  --n100: #f0f3f7;
  --n200: #e0e4ec;
  --n300: #cacfd9;
  --n400: #9ba2b0;
  --n500: #7f8594;
  --n600: #616775;
  --n700: #494d59;
  --n800: #3e414d;
  --n900: #343843;
  --n930: #2b2f3a;
  --n960: #262a34;
  --light-red: #ffa8b5;
  --light-orange: #ffbab0;
  --light-yellow: #ffe7b2;
  --light-green: #7fd9df;
  --light-blue: #77b2ff;
  --light-purple: #9689ff;
  --dark-red: #dc596d;
  --dark-orange: #e16a58;
  --dark-yellow: #e4ac31;
  --dark-green: #1d9da6;
  --dark-blue: #3a7fd8;
  --dark-purple: #695dd0;
  --light-brown: #b9968e;
  --brown: #a87c72;
  --dark-brown: #9a695e;
}

* {
  box-sizing: border-box;
}

html {
  font-family: NanumSquareNeo-Variable, sans-serif;
  font-size: 16px;
}

body {
  margin: 0 auto;
  padding: 16px;
  max-width: 720px;
  width: 100%;
}

a {
  color: var(--purple);
}

.heading > .accent {
  color: var(--purple);
  font-size: 1.5em;
  font-weight: 900;
}

.product-image {
  width: 100%;
}

body.full-height {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  margin: 0;
  padding: 0;
}

.full-height-content {
  flex-grow: 1;
  padding: 16px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.full-height-footer {
  flex-shrink: 0;
  padding: 16px;
  background-color: var(--n200);
}

▶ JS 파일

더보기
//  cookie-helper.js 

function isCookieExist(name) {
  const encodedName = encodeURIComponent(name);
  return document.cookie
    .split('; ')
    .find((cookie) => cookie.startsWith(encodedName))
    ? true
    : false;
}

function getCookieValue(name) {
  const encodedName = encodeURIComponent(name);
  const cookies = document.cookie.split('; ');
  const targetCookieValue = cookies
    .find((cookie) => cookie.startsWith(encodedName))
    ?.split('=')[1];
  return targetCookieValue ? decodeURIComponent(targetCookieValue) : undefined;
}

function setCookie(name, value) {
  document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);
}

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);
      setCookieWithOptions('no-popup', true, {
        expires: tomorrow,
      });
    } else {
      deleteCookie('no-popup');
    }
  });
}

setEventListeners();
//  script.js

function showPopUp() {
  window.open('popup.html', 'popup', 'width=420, height=640');
}

window.onload = () => {
  if (!isCookieExist('no-popup')) {
    showPopUp();
  }
};

 

반응형