JavaScriptではcookieの取得・保存・削除を行うことができます。
そんなcookieを使って、ユーザーが選択した「記事一覧レイアウト」の設定を、ページ離脱後も生かすJavaScriptのスニペットについて解説していきます。
JavaScriptの document.cookie
は、Webブラウザ上に保存された情報のcookieを読み書きすることができます。
JavaScriptでcookieを追加する時、以下のような記述をします。
document.cookie = 'value=クッキー名; max-age=9999';
max-age
はそのcookieの寿命で表され、上記のような9999だと大体3時間弱です。
value
のところは任意の名称でOKです。
追加したcookieを削除する場合、max-age
の値を0に設定して、Cookieを有効期限切れにすることで削除の扱いにします。
document.cookie = "value=cookie名;max-age=0;";
記事一覧のサンプル
ここで選択したレイアウトは、ページ遷移や更新をしても生きる形です。ので、試してみる場合は「カード」のレイアウトを選択してから、そのままページ更新をしてみてください。
cookieを使っているので、ブラウザを閉じてから開いても選択した設定が生きます。
コードは、HTML・JavaScript・CSSの3種です。順に解説していきます。
HTML
HTMLは大きく分けて、「レイアウトを変更するボタン」の要素と、「記事一覧」の2つでできています。
コード量は記事一覧に関するものがほとんどで、各記事のコンポーネントは li
のリストタグで作っています。
<!-- レイアウト変更のボタンここから -->
<ul class="cookieSwitch">
<li><p id="styleList" class="activeOn"><i class="fas fa-th-list"></i>リスト</p></li>
<li><p id="styleCard"><i class="fas fa-th-large"></i>カード</p></li>
</ul>
<!-- レイアウト変更のボタンここまで -->
<!-- 記事一覧のレイアウト -->
<section class="SwitchBlock">
<div class="changeCard">
<ul>
<li class="changeItem defaultList">
<a href="https://dubdesign.net/javascript/addeventlistener-scroll/">
<p class="itemCat dfont">JavaScript ネタ帳</p>
<img src="https://dubdesign.net/wp-content/uploads/2021/12/java003.jpg" alt="JavaScriptの.addEventListenerのスクロールでclassの追加と削除">
<div class="changeItemTxt">
<time class="pubdate sng-link-time dfont" itemprop="datePublished" datetime="2021年12月15日">2021年12月15日</time>
<p class="itemTitle">JavaScriptの.addEventListenerのスクロールでclassの追加と削除</p>
<ul class="itemTag">
<li>JavaScript</li><li>コピペ</li><li>スクロール</li></ul>
</div>
</a>
</li>
<li class="changeItem defaultList">
<a href="https://dubdesign.net/download/html-css/javascript-yubinbango/">
<p class="itemCat dfont">HTML・CSS</p>
<img src="https://dubdesign.net/wp-content/uploads/2021/08/yuubinnbangou_eyecatch.jpg" alt="JavaScriptのコピペでできる郵便番号を入力すると住所を自動で表示してくれるプラグインYubinBango">
<div class="changeItemTxt">
<time class="pubdate sng-link-time dfont" itemprop="datePublished" datetime="2021年8月4日">2021年8月4日</time>
<p class="itemTitle">JavaScriptのコピペでできる郵便番号を入力すると住所を自動で表示してくれるプラグインYubinBango</p>
<ul class="itemTag">
<li>CSS</li><li>HTML</li><li>JavaScript</li></ul>
</div>
</a>
</li>
<li class="changeItem defaultList">
<a href="https://dubdesign.net/javascript/hover-tooltip/">
<p class="itemCat dfont">JavaScript ネタ帳</p>
<img src="https://dubdesign.net/wp-content/uploads/2022/02/javatooltip.jpg" alt="JavaScriptの.addEventListener()でhoverした時ツールチップを表示">
<div class="changeItemTxt">
<time class="pubdate sng-link-time dfont" itemprop="datePublished" datetime="2022年2月23日">2022年2月23日</time>
<p class="itemTitle">JavaScriptの.addEventListener()でhoverした時ツールチップを表示</p>
<ul class="itemTag">
<li>JavaScript</li><li>コピペ</li><li>ツールチップ</li></ul>
</div>
</a>
</li>
<li class="changeItem defaultList">
<a href="https://dubdesign.net/admiration/tail-grafic/">
<p class="itemCat dfont">見て学ぶデザイン</p>
<img src="https://dubdesign.net/wp-content/uploads/2020/05/0503_tairu_eyecatch.jpg" alt="イラストや写真をタイルのように隙間無く敷き詰めたデザイン">
<div class="changeItemTxt">
<time class="pubdate sng-link-time dfont" itemprop="datePublished" datetime="2020年5月3日">2020年5月3日</time>
<p class="itemTitle">イラストや写真をタイルのように隙間無く敷き詰めたデザイン</p>
<ul class="itemTag">
<li>広告</li></ul>
</div>
</a>
</li>
</ul>
</div>
</section>
<!-- 記事一覧のレイアウトここまで -->
ボタン内のアイコンはFontawesomeを使っています。
JavaScript
JavaScriptは、「ページロード時のcookieチェック」と「ボタンクリック時の処理」の2つで、これらを .addEventListener
の「DOMContentLoaded=HTMLの配置が完了次第」と、「click=クリック」のイベントでそれぞれ分けて作っています。
/* ロード時のcookie有無チェック */
window.addEventListener('DOMContentLoaded', (event) => {
/* cookieを取得 */
function getCookieArray(){
var arr = new Array();
if(document.cookie != ''){
var tmp = document.cookie.split('; ');
for(var i=0;i<tmp.length;i++){
var data = tmp[i].split('=');
arr[data[0]] = decodeURIComponent(data[1]);
}
}
return arr;
}
var arr = getCookieArray();
var result = arr["value"];
/* valueのcookieがない時 */
if(result == null){
console.log("no cookie");
} else {
var theme = result;
if(theme == 'cardCookie'){
/* valueの値でcardCookieがある時 */
var elements = document.getElementsByClassName("changeItem");
var i;
for (i = 0; i < elements.length; i++) {
elements[i].classList.remove('defaultList');
elements[i].classList.add('gridCard');
}
document.getElementById("styleCard").classList.add('activeOn');
document.getElementById("styleList").classList.remove('activeOn');
console.log('CardStyle');
} else {
/* valueの値でcardCookieがない時 */
var elements = document.getElementsByClassName("changeItem");
var i;
for (i = 0; i < elements.length; i++) {
elements[i].classList.remove('gridCard');
elements[i].classList.add('defaultList');
}
document.getElementById("styleList").classList.add('activeOn');
document.getElementById("styleCard").classList.remove('activeOn');
console.log('notCardStyle');
}
}
});
/* リストへ変更 */
document.querySelector('#styleList').addEventListener('click', () => {
var elements = document.getElementsByClassName("changeItem");
var i;
for (i = 0; i < elements.length; i++) {
elements[i].classList.remove('gridCard');
elements[i].classList.add('defaultList');
}
document.getElementById("styleList").classList.add('activeOn');
document.getElementById("styleCard").classList.remove('activeOn');
document.cookie = "value=cardCookie;max-age=0;";
console.log('cookieDelete');
});
/* カードへ変更 */
document.querySelector('#styleCard').addEventListener('click', () => {
var elements = document.getElementsByClassName("changeItem");
var i;
for (i = 0; i < elements.length; i++) {
elements[i].classList.remove('defaultList');
elements[i].classList.add('gridCard');
}
document.getElementById("styleCard").classList.add('activeOn');
document.getElementById("styleList").classList.remove('activeOn');
document.cookie = 'value=cardCookie; max-age=9999';
console.log('cookieGet');
});
特に冒頭の「ページロード時のcookieチェック」は、ifの条件分岐で処理を分けているので、一緒に記述してあるコメントアウトと共にご覧ください。
CSS
レイアウトはFlexboxを使い、JavaScriptでclassを付け替えた時にCSSが紐づき表示を切り替えます。
その為、CSSはレイアウトに関する記述がほとんどになっています。
/* ボタンのレイアウト */
ul.cookieSwitch {
border: none;
padding: 0;
list-style: none;
display: flex;
justify-content: flex-end;
flex-wrap: wrap;
margin: 0;
gap: 20px;
}
ul.cookieSwitch li p {
margin: 0;
display: inline-block;
cursor: pointer;
padding: 5px 20px 3px;
background: #ddd;
color: #FFF;
border-radius: 2px;
font-size: 0.9rem;
}
ul.cookieSwitch li p.activeOn {
background: #707070;
}
ul.cookieSwitch li p i {
margin-right: 5px;
}
/* ボタンここまで */
/* レイアウト共通 */
.changeCard ul {
padding: 0;
list-style: none;
border: none;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: 0;
margin-top: 5px;
}
.changeItemTxt {
width: 62%;
}
.changeItemTxt p.itemTitle {
font-size: 1.1rem;
line-height: 1.56;
margin: 0;
font-weight: bold;
color: #313131;
margin-bottom: 10px;
}
.changeItemTxt ul.itemTag {
padding: 0;
margin: 0;
display: flex;
justify-content: flex-start;
align-items: center;
flex-wrap: wrap;
gap: 10px;
}
.changeItemTxt ul.itemTag li {
background: #f1f1f1;
color: #707070;
font-size: 0.7rem;
padding: 2px 10px;
position: relative;
}
.changeItemTxt ul.itemTag li:before {
padding-right: 3px;
font-family: "Font Awesome 5 Free";
font-weight: 900;
font-size: 1em;
content: "\f02b";
vertical-align: baseline;
color: #aaa;
}
p.itemCat {
position: absolute;
left: 22px;
top: 22px;
background: #6bb6ff;
color: #FFF;
border-radius: 9999px;
font-size: 0.7rem;
display: inline-block;
padding: 1px 12px 0px;
z-index: 2;
}
/* 共通ここまで */
/* List */
li.changeItem.defaultList {
width: 100%;
padding: 0;
}
li.changeItem.defaultList a {
display: flex;
flex-direction: row;
flex-wrap: wrap;
border-radius: 2px;
background: #fff;
cursor: pointer;
transition: 0.2s ease-in-out;
padding: 15px;
position: relative;
align-items: center;
text-decoration: none;
border-top: solid 1px #eee;
padding-right: 10px;
cursor: pointer;
}
li.changeItem.defaultList:last-child a {
border-bottom: solid 1px #EEE;
}
li.changeItem.defaultList a:hover {
background: #fafafa;
}
li.changeItem.defaultList a img {
width: 35%;
margin-right: 3%;
}
@media screen and (max-width: 767px) {
/* (ここにモバイル用スタイルを記述) */
li.changeItem.defaultList a {
flex-direction: column;
}
li.changeItem.defaultList a img {
width: 100%;
margin: 0 0 15px;
}
li.changeItem.defaultList a .changeItemTxt {
width: 100%;
}
}
/* GridCard変更後 */
li.changeItem.gridCard {
width: 47.5%;
margin-bottom: 30px;
}
li.changeItem.gridCard a {
display: flex;
flex-direction: column;
border: none;
border-radius: 2px;
background: #fff;
box-shadow: 0 0 3px 0 rgb(0 0 0 / 12%), 0 2px 3px 0 rgb(0 0 0 / 22%);
cursor: pointer;
transition: 0.2s ease-in-out;
height: 100%;
padding: 0;
position: relative;
text-decoration: none;
}
li.changeItem.gridCard a:hover {
box-shadow: 0 15px 30px -5px rgb(0 0 0 / 15%), 0 0 5px rgb(0 0 0 / 10%);
transform: translateY(-4px);
}
li.changeItem.gridCard a p.itemCat {
top: 10px;
left: 10px;
}
li.changeItem.gridCard a .changeItemTxt {
width: 100%;
padding-left: 18px;
padding-right: 18px;
padding-bottom: 10px;
}
li.changeItem.gridCard a img {
width: 100%;
margin: 0 0 12px;
}
li.changeItem.gridCard .changeItemTxt ul.itemTag {
display:none;
}
@media screen and (max-width: 767px) {
/* (ここにモバイル用スタイルを記述) */
li.changeItem.gridCard {
width: 100%;
margin-bottom: 20px;
}
}