マイページを作った話

# はじめに(軽く自己紹介を...)

今年度、駒場祭において、「マイページ」というページを実装しました。
htmlすら触るのがほぼ初めてだった私が、このマイページというページを仕様書の作成段階から(一応は)作り上げたました。その実装過程で、localStorageやqueryパラメータなどの機能を用いたので、その経緯を是非ともご紹介したいと思い、この記事を書いております。

> ここから、始めましょう。一から……いいえ、ゼロから！

# 駒場祭公式ウェブサイト/マイページについて

今年度、駒場祭公式サイトの新たな試みとして、お気に入り登録機能と、お気に入り登録した企画等を表示するマイページを作成するというプロジェクトが持ち上がりました。
実際に完成したものは[ここ](https://www.komabasai.net/70/visitor/mypage)から見てみてください。

# 仕様の決定

## Cookie取得の難点

「お気に入り情報を登録」と聞くと、最初に挙げられる選択肢はおそらくCookieではないでしょうか。
私たちもはじめは、Cookieを取得することで、ユーザーの変更を保存しようと考えました。

しかし、ここで問題が生じます。  
EUの「GDPR(一般データ保護規則)」などの影響で、ユーザーのcookie取得の際にユーザーの同意等が必要となるのです。
この、cookieの取得に対する是非を何回も聞かれるようでは非常に面倒になります。というわけで、とりあえずはcookie以外の方法を考えることにしました。

## localStorageという選択

さて、cookie取得を封じたとして、ではなにを使おうか...となったときに見つけたのが、「localStorage」でした。localStorageは、簡単に言ってしまえば、「ブラウザに情報を保存する」機構です。
これを用いれば、お気に入りボタン的なのを押して、対応する企画idを一旦localStorageに保存することで、マイページにお気に入り登録した企画を表示できるようになりました。
ですが、このlocalStorage、上で紹介したように、「ブラウザに」情報を保存するものですので、次にブラウザ間のデータのやり取りと、他の媒体で情報を取得することを考えました。

## ログイン機構の難点

お気に入りした情報をいかに保存、他の媒体で閲覧できるようにするか。
まず最初に思いついたのが「ログイン」機構です。

ですが、ここにも問題があります。ログイン情報の取得は「個人情報の取得」に該当することがあり、ユーザーに利用規約を提示し、同意をもらう必要が生じかねません。
しかし、お気に入り登録のデータを見るくらいのページでユーザーにそこまで求めてしまっては、ユーザビリティが低下してしまいます。

そうこうしているうちに公開日が迫ってきたので、とりあえずはログイン機構もデータの受け渡しも実装しないまま、第1版を公開しました。

## シェアとクエリパラメータの導入

さて、とりあえず暫定的にデータの受け渡し機構を作らないまま公開をしましたが、やはり受け渡しをしないわけにもいきません。

色々考えて出てきたのが、「URLのクエリパラメータ」です。これは、URLの後ろに```/?x=hogehoge```のような感じで値をのせることができます。
この```x```や```hogehoge```の部分に、お気に入りした企画などのグッズの情報をのせてURLを作成すれば、QRコードを作ったり、Twitter/LINEなどでシェアする用のボタンを作ることができます。

検討の結果、今回はこれを導入することにしました。

# 実装

## localStorageの面倒臭さ

実装段階に入ります。まずはお気に入り用の星を作成しました。
対応する企画のidをlocalStorageに保存する機構を作ろうと思ったのですが、ここで問題が…

localStorageに格納できるデータは、「文字列」だけなのです。すなわち、idを配列として保存することができないのです。

そこで取った方法ですが、まず、js部分で配列を生成し、これを```JSON.stringfy```を用いてString型にしてlocalStorageに保存する。
逆にlocalStorageに保存したデータを読み込むときは、文字列を取ってきて、これを```JSON.parse```を用いてObject型にして配列として読み込む。
ということをしました。実際のコードは以下の通り。

```Javascript
// 保存部分
let favoriteKikaku = []
favoriteKikaku.push(this.id);
localStorage.setItem('favoriteKikaku', JSON.stringify(favoriteKikaku));
```

```Javascript
// 読み込み部分
let favoriteKikaku = localStorage.getItem('favoriteKikaku');
favoriteKikaku = JSON.parse(favoriteKikaku);
let favoriteKikakuId = '';
for(let k=0;k<favoriteKikaku.length;k++){
    favoriteKikakuId += favoriteKikaku[k];
    if(k!=favoriteKikaku.length-1) favoriteKikakuId+=',';
}
```

読み込み部分ですが、最後のfor文、```[xxx, xxx, xxx, xxx]```という形の配列に格納されているidを```xxx, xxx, xxx, xxx```という形に変えてるんですが…
今見返してみると、汚いコードですね…
```relpace```を知らないんですかね…

まぁ、ここまで書いたらだいたいlocalStorageのお気持ちを理解できたし、これでlocalStorage部分はほぼ完成しました。
なので、ここまでで初回公開にしました。

## クエリパラメータの付与

さて、次にすることはクエリパラメータ付与したURLを生成することです。

まず、クエリパラメータの仕様ですが、

```
https://hogehoge.net/?f1=xxx,xxx,xxx&f2=yyy,yyy,yyy
```

こうあったときに、最後の```?```以降がクエリパラメータとなります。その後は  
```"key"=String&"key"=String```
というように、続きます。

実際のコードを見てみましょう。

```Javascript
let kikakuURL = JSON.parse(localStorage.getItem('favoriteKikaku'));
this.postingKikakuURL = JSON.stringify(kikakuURL);
this.postingKikakuURL=this.postingKikakuURL.replace(/]/g, "");
this.postingKikakuURL=this.postingKikakuURL.replace(/\[/g, "");
this.postingKikakuURL=this.postingKikakuURL.replace(/:/g, "=")
this.postingKikakuURL=this.postingKikakuURL.replace(/"/g, "");

let goodsURL = JSON.parse(localStorage.getItem('favoriteGoods'));
this.postingGoodsURL = JSON.stringify(goodsURL);
this.postingGoodsURL=this.postingGoodsURL.replace(/]/g, "");
this.postingGoodsURL=this.postingGoodsURL.replace(/\[/g, "");
this.postingGoodsURL=this.postingGoodsURL.replace(/:/g, "=")
this.postingGoodsURL=this.postingGoodsURL.replace(/"/g, "");

this.shareURL = 'https://www.komabasai.net/70/visitor/mypage?kikaku='+this.postingKikakuURL+'&goods='+this.postingGoodsURL;
```

// こいつ、ようやく```replace```を覚えたんですね。

さて、ここでやっていることですが……見たらわかりますかね…  
まずlocalStorageから文字列を持ってきて、これを```replace```でクエリパラメータとして変換できる形にしています。
ここで言う"クエリパラメータとして変換できる形"ですが、上でも挙げたように、基本的には```key=Value```の形になっているものをさします。

## クエリパラメータを読む

次にやったのは、上で付与したクエリパラメータを読む機構の作成です。
今回は、クエリパラメータで渡された企画のidを、パラメータを読み込んだブラウザのlocalStorageに"追加"で保存するようにしました。

コードは以下のような感じですね。やっていることは単純です

```Javascript
let queryKikakuList = (this.$route.query.kikaku || "").split(',');
let queryGoodsList = (this.$route.query.goods || "").split(',');
if (queryKikakuList == ""){}
else {
    if (localStorage.getItem('favoriteKikaku') == null){
        let favoriteKikaku = []
        for ( let i=0; i<queryKikakuList.length; i++) {
            favoriteKikaku.push(Number(queryKikakuList[i]));
        }
        localStorage.setItem('favoriteKikaku', JSON.stringify(favoriteKikaku));
    } else {
        let favoriteKikaku = localStorage.getItem('favoriteKikaku');
        favoriteKikaku = JSON.parse(favoriteKikaku);
        for ( let i=0; i<queryKikakuList.length; i++) {
            if (favoriteKikaku.some(value => value == queryKikakuList[i])) {
            } else {
                favoriteKikaku.push(Number(queryKikakuList[i]));
                console.log(queryKikakuList);
            };
        }
        localStorage.setItem('favoriteKikaku', JSON.stringify(favoriteKikaku));
    }
}
```

## 二次元コードの生成

URLを作っても、それをどうにかして別のデバイスや別ブラウザに送らなくてはなりません。そのために今回は、「URLコピーのボタン」「LINEでシェアボタン」「Twitterでシェアボタン」「QRコード」の4つを表示することにしました。

そのうちのQRコードの生成なのですが、Google Chart APIを使いました。
こいつ自体の使い方は非常に簡単です。

以下、コード

```Javascript
document.getElementById('qr').src = "http://chart.apis.google.com/chart?cht=qr&chs=130x130&chco=ED6D2B&chl=https://www.komabasai.net/70/visitor/mypage?kikaku="+this.postingKikakuURL+'&goods='+this.postingGoodsURL;
```

このように、imgのsrcの部分に、

```
http://chartapis.google.com/chart?cht=qr&chs={{サイズ}}&chco={{カラーコード(＃はいらない)}}&chl={{QRのURL}}
```

を入力すれば表示できます。

# 改善点

- フロントの実装のときにTabのようなものを実装したが、これの実装に名前付きビューを使っていた方が後々見やすかったかなぁ...
- localStorageへのデータの保存ですが、保存が完了するまでに少し時間がかかるため、早くにページを閉じてしまうと、お気に入りの情報が飛んでしまったようです…
- その他、localStorageまわりで、データが飛ぶ等のバグ報告を少し受けたので、次回までには原因究明と修正ができたらな...と思っています

# まとめ

- GDPR対策で、Cookieを取得しないとなると、代替案を探すのが少々面倒
- localStorageはGDPR的には良いのだが、使いづらい点もある
- queryパラメータは積極的に使っていきたい

さて、ここまで読んでいただきありがとうございます。
初投稿かつ、やってきたことをタレ流した記事だったので、読み苦しいものであったかもしれませんが、ご容赦ください。
また、GDPR周りについては詳しくは知らないことも多く、多少間違った理解をしているかもしれません。その場合は遠慮なくコメント等でご指摘ください。

マイページのようなページの実装にlocalStorageやqueryパラメータを使うことが一般的なのかはわかりませんが、こういう方法もあるんだと思っていただければ幸いです。

最後になりますが、来年度の第71回駒場祭でもウェブサイトは制作する予定なので、来年の11月ごろにぜひ「駒場祭」で検索してみてください。