G’s ACADEMY LABコース学習記録 #3(Web Strage使ってみた)

プログラミング初心者の勉強ブログ #114

G’s ACADEMY LABコース学習記録。今回は最初のHTML/CSSの課題であった企業HP作成で、Web Strageを使ってみたことについて書く。ストレージ、セッション、キャッシュ、クッキーなどとややこしいのでそこら辺のブラウザ機能を一回整理していく。

 

目次

[toc]

 

Web Strage

Web Storage API は、Cookie を使用するよりも直感的な方法で、ブラウザがキーと値のペアを保存できる仕組みを提供します。

Web Storage API – Web API | MDN

難しく書かれているが、Web Storageはとにかくブラウザにデータを保存できる仕組みである。

 

ディベロッパーツールで確認するのが早い。

ディベロッパーツール Application画面

Application画面をみると、左に「Strage」やら「Session」やら「Cookie」やら「Cache」やら、正確に違いを説明しろと言われると難しい群が列をなしている。

Strageは2種類ある。Local StrageとSession Strage。そしてそのディレクトリの中に、URLに紐づいてファイルが作成されている。

ファイルの中身は単純で、KeyとValueというハッシュの構造で構成され、ここに任意のデータを保存するイメージ。上の場合、「cheese1: 100」と「cheese1_count: 1」が入っている。

これらはJavaScriptを書くことで保存や更新、削除、取り出しができる。Web Storage APIをJavaScriptの記述により呼び出すイメージ。

 

Session、Cookie、Cacheの確認

ここで今一度セッションとキャッシュとクッキーを確認する。

Session

セッション (session)とは「こんにちは」から「さようなら」まで(を意図する単位)。もう少し真面目っぽく書くと論理的な意味での「開始」から「終了」まで(を意図する単位)です。

セッション (session)とは|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

セッションはユーザーとサーバのやりとり・手続きそのものを意味する。

セッションにはIDがついていて、どのユーザと、どのサーバのやりとりかを一意に識別するためのものである。サーバ側がIDを発行し、ユーザ側に渡す。このセッションIDが次に出てくるクッキーとしてブラウザに保存される。

セッション情報そのものはWebサーバ側に保存されている。2回目以降の通信はユーザ側から渡されたセッションIDをもとに、一致するセッション情報を探すイメージ。

 

Cookie

クッキー (cookie)とは、ホームページのファイルが置いてあるコンピュータ(Webサーバ)からホームページを見るソフト(Webブラウザ)に「次に来るときは、これを持ってきてね」と、こっそり渡されるメモのことです。

クッキー (cookie)とは|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

このメモに当たるのが、さっきのセッションIDである。渡されたクッキーはWebブラウザに保存される。クッキーは「ユーザ情報」を保持する機能。「ユーザ情報」という点が、次のキャッシュとクッキーを区別して覚えるのに大切。

 

Cache

キャッシュ (cache)とは、よく使うデータを取り出しやすいところに準備しておく仕組みのことです。

キャッシュ (cache)とは|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

キャッシュも先ほどのクッキーと同様に、Webブラウザに保存される。クッキーがユーザとサーバを紐づける情報を保持するに対し、キャッシュは「Webページの情報」を保持する機能となる。

 

まとめると

セッション、キャッシュ、クッキーは、保存場所で区別すると、

  • Webサーバ  → セッション
  • Webブラウザ → キャッシュ、クッキー

となる。そして、キャッシュとクッキーは、

  • Webページの情報 → キャッシュ
  • ユーザの情報   → クッキー

といった形で区別する。

 

実際にWeb Storageを使ってみる

とりあえず使う。今回はLocal Strageで例を挙げる。Local StrageとSession Stageの違いは、ブラウザを閉じたり開いたり、別タブを開いてみたりしたときに全てに反映されるのがLocal Strage。そうでないのがSession Stage。Session Stageはセッション中のみ使用可能なストレージということ。

 

作成したもの

webstragegif

動画

クリックしたらそのチーズの情報と回数がLocal Strageに保存され、表示が変わる。Local Strageである必要は特にない。

 

実際のコード

リファクタリングできてないので汚い。「ITEMS」のモーダルは、要素の生成を全てJSでやってみており、HTMLには何も書き込んでいない。とりあえず素のJSをかく練習も兼ねている。

※Local Strageへの保存は、

Web Storageの使い方 – Qiita

ここを参考。

 

main.js(抜粋)

(() => {
  "use strict";

  const body = document.getElementsByTagName('body');
  const secTitle = 'ITEMS';
  const array = [
    {title: 'cheese1',
     price: '100',
     image: './img/item01.jpg'
    },
    {title: 'cheese2',
     price: '200',
     image: './img/item02.jpg'
    },
    {title: 'cheese3',
     price: '300',
     image: './img/item03.jpg'
    },
    {title: 'cheese4',
     price: '400',
     image: './img/item04.jpg'
    },
    {title: 'cheese5',
     price: '500',
     image: './img/item05.jpg'
    },
  ];

  // モーダル生成
  const initItemSection = function() {
    const overlay = document.createElement('div');
    const itemsSection = document.createElement('section');
    const secTtl = document.createElement('h3');
    const itemList = document.createElement('div');
    const itemsCloseBtn = document.createElement('div');
    const cartList = document.createElement('div');

    for (let i = 1; i <= 2; i++) {
      let div = document.createElement('div');
      div.className = `closs${i}`;
      itemsCloseBtn.appendChild(div);
    };

    overlay.className = 'overlay';
    itemsSection.className = 'items';
    secTtl.className = 'secTtl';
    itemList.className = 'items__list items-list';
    itemsCloseBtn.className = 'items__closeBtn';
    cartList.className = 'items__cart items-cart';

    secTtl.innerHTML = secTitle;
    setItems(array, itemList);
    setCartItems(cartList);

    itemsSection.appendChild(itemsCloseBtn);
    itemsSection.appendChild(secTtl);
    itemsSection.appendChild(itemList);
    itemsSection.appendChild(cartList);

    overlay.appendChild(itemsSection);

    $('#items').on('click', function() {
      body[0].appendChild(overlay);
    });
    itemsCloseBtn.addEventListener('click', function() {
      overlay.remove();
    });
  };

  // 商品生成
  const setItems = function(array, itemList) {
    array.forEach(function(item) {
      const itemContent = document.createElement('div');
      const itemImg = document.createElement('img');
      const itemTtl = document.createElement('p');
      const itemPrice = document.createElement('span');

      itemContent.className = 'items-list__content';

      itemImg.src = item.image;
      itemTtl.innerHTML = item.title;
      itemPrice.innerHTML = '¥ ' + item.price;

      itemContent.addEventListener('click', function(){
        const itemName = this.children[1].innerHTML;
        const itemPrice = this.children[2].innerHTML.slice(2);

        let itemCount = 1;
        if (localStorage[itemName]) {
          itemCount += Number(localStorage[`${itemName}_count`]);
        } else {
          localStorage.setItem(itemName, itemPrice);
        };

        localStorage.setItem(`${itemName}_count`, itemCount);

        let cartList = document.getElementsByClassName('items__cart');
        const itemsSection = document.getElementsByClassName('items');

        cartList[0].textContent = null;
        setCartItems(cartList[0]);
        itemsSection[0].appendChild(cartList[0]);
      });

      itemContent.appendChild(itemImg);
      itemContent.appendChild(itemTtl);
      itemContent.appendChild(itemPrice);

      itemList.appendChild(itemContent);
    });
  };

  // 下の金額部分
  const setCartItems = function(cartList) {
    let totalPriceSum = 0;
    const cartItemTotalPriceSum = document.createElement('div');
    const clearBtn = document.createElement('p');
    clearBtn.innerHTML = "clear";
    clearBtn.addEventListener('click', function(){
      const items = array.map(function(item){
        return item.title
      });
      items.forEach(function(item) {
        localStorage.removeItem(`${item}`);
        localStorage.removeItem(`${item}_count`);
      });
      let cartList = document.getElementsByClassName('items__cart');
      const itemsSection = document.getElementsByClassName('items');

      cartList[0].textContent = null;
      setCartItems(cartList[0]);
      itemsSection[0].appendChild(cartList[0]);
    });

    for (let i = 0; i < localStorage.length; i++) {
      const cartContent = document.createElement('ul');
      const cartItemName = document.createElement('li');
      const cartItemPrice = document.createElement('li');
      const cartItemCount = document.createElement('li');
      const cartItemPriceSum = document.createElement('li');

      const key = localStorage.key(i);
      cartContent.className = `items-cart__content ${key}_list`;

      const items = array.map(function(item){
        return item.title
      });
      items.forEach(function(item) {
        if (key === item) {
          let value = Number(localStorage[key]);
          let count = Number(localStorage[`${key}_count`]);
          
          cartItemName.innerHTML = key;
          cartItemPrice.innerHTML = '¥ ' + value;
          cartItemCount.innerHTML = '× ' + count;
          cartItemPriceSum.innerHTML = value * count;

          totalPriceSum += value * count;

          cartContent.appendChild(cartItemName);
          cartContent.appendChild(cartItemPrice);
          cartContent.appendChild(cartItemCount);
          cartContent.appendChild(cartItemPriceSum);

          cartList.appendChild(cartContent);
        };
      });
    };
    cartItemTotalPriceSum.innerHTML = totalPriceSum;
    if (cartList.children !== null) {
      cartList.appendChild(cartItemTotalPriceSum);
      cartList.appendChild(clearBtn);
    };
  };


  initItemSection();
})();

 

style.css(抜粋)

/* items */
.overlay {
  width: 100%;
  height: 100vh;
  position: absolute;
  z-index: 2;
  top: 0;
  background: rgba(0, 0, 0, 0.7);
  box-sizing: border-box;
  padding: 50px;
}
.items {
  width: 100%;
  height: 100%;
  background: #fff;
  border-radius: 5px;
  box-sizing: border-box;
  padding: 50px;
}
.items__closeBtn {
  width: 80px;
  height: 80px;
  position: absolute;
  top: 70px;
  right: 70px;
  cursor: pointer;
}
.items__closeBtn .closs1 {
  width: 50px;
  height: 1px;
  background: #222;
  position: absolute;
  transform: rotate(45deg);
  top: 40px;
  left: 16px;
}
.items__closeBtn .closs2 {
  width: 50px;
  height: 1px;
  background: #222;
  position: absolute;
  transform: rotate(-45deg);
  top: 40px;
  left: 16px;
}
.items__list {
  display: flex;
  justify-content: space-evenly;
  margin: 50px 0 0;
} 
.items-list__content {
  cursor: pointer;
  overflow: hidden;
}
.items-list__content:hover img{
  opacity: 0.7;
}
.items-list__content img {
  transition: 0.2s ease-out;
  width: 150px;
  height: 150px;
}
.items-list__content p {
  font-family: 'Roboto Slab', serif;
  letter-spacing: 0.1em;
  font-weight: bold;
  font-size: 18px;
  padding: 10px 0;
}
.items-list__content span {
  font-family: 'Roboto Slab', serif;
  letter-spacing: 0.1em;
}
.items__cart {
  box-sizing: border-box;
  margin: 50px auto 30px;
  width: 430px;
}
.items__cart div{
  border-top: solid 1px #ddd;
  line-height: 35px;
  letter-spacing: 0.1em;
  text-align: right;
  box-sizing: border-box;
  padding: 10px 30px 0 0;
  font-weight: bold;
}
.items__cart p {
  margin-top: 10px;
  text-align: center;
}
.items-cart__content {
  display: flex;
}
.items-cart__content li {
  width: 100px;
  line-height: 35px;
  letter-spacing: 0.1em;
}
.items-cart__content li:first-child {
  font-weight: bold;
  width: 130px;
}
.items-cart__content li:last-child {
  text-align: right;
  width: 70px;
}

 

まとめ

Web Strageをやるという名目のもとJSの練習をしていた気がする。ドットインストールで学んだリファクタリングをしたいが、授業があると今までみたいに時間を簡単に割けない。とりあえず電車間に合わないのでこれで終わります。

以上ありがとうございました。

返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA