HistoryAPIとキャッシュマニフェストについて

本来URLは**web上のコンテンツを一意に認識するために利用される。**しかし、Ajaxを利用するとページ遷移がなくてもコンテンツを書き換えられるため、同一のURLが異なるコンテンツを指してしまう事が起こる。これでは、ブックマークも機能せず、外部からリンクを貼ることもできなくなる。


###ハッシュフラグメントの利用
`URLの#以降の文字列のこと。`


本来ページ内リンクで利用されるもので、**ハッシュフラグメントが変わってもページ遷移は起きない。**この仕組を利用してページの状態をハッシュフラグメントにもたせることで、**アプリケーションの特定の状態に一意のURLを割り当てることができる。**


```js:js
//状態の保存
function goPage(num) {
  updateContents(num); //ページ遷移を発生させる関数を仮に設定
  location.hash = '#!page=' + num; //ハッシュフラグメントに状態を保存
}

//状態の復元
window.onhashchange = function() {
  let num = location.hash.match(/#!page=([0-9]+)/)[1]; //ハッシュフラグメントから状態を取得
  updateContents(num);
}
```

**フラグメントは[#!]から始める。**
これはクローラの仕様として、[#!]を含むURLをAjaxアプリケーションとして判断し適切な処理を行ってくれる。Ajax処理では[#!]を利用する。
<br>
<br>

しかし、これらの処理は本来のハッシュフラグメントの用途とは異なるため懸念の声もある。その問題をスマートに解決してくれたのがHistoryAPI.


##HistoryAPI
* JSからブラウザの履歴情報やURLを操作するためのAPI
* ページ遷移を発生させずに、URLを任意のものに書き換えることができる

今まででは、URL更新には2通りの書き方

**通常のページ遷移**

```js:js
// /search/foo へのページ遷移
 location.href = '/search/foo';
```
**ハッシュフラグメントを利用したURL更新**

```js:js
//ajax的に状態遷移
  updateContents('/search/foo'); //ajaxで遷移させる関数だと仮定
  location.hash = '#!/search/foo'; //ハッシュフラグメントを変更
```

今回HistoryAPIの、**pushStateメソッド**を利用することで、URLを適切な状態に変更することができる。

```js:js
//ajax的に状態遷移
  updateContents('/search/foo'); //ajaxで遷移させる関数だと仮定
  history.pushState(null, 'ページのタイトル', '/search/foo'); //URLを変更
```
<br>
###ページの履歴移動

```js:js
//履歴をひとつ戻る
history.back();

//履歴を一つ進む
history.forward();

//履歴を2つ戻る
history.go(-2);
```

###popstateイベント
* popstateイベントはページの履歴をたどったときに発火するイベント。
* popstateイベントを監視してページの状態を復元する処理などを実装。


**ページ状態の復元処理**

```js:js
window.onpopstate = function() {
  //substringメソッドで「/search/foo」文字列の１番目からの文字列を取得。
  //splitは文字列を分割して配列化。[search, foo]となる。
  let pathname = location.pathname.substring(1).split('/');

  switch(pathname[0]) {
    case 'list';
     //処理
    case 'search'
     //処理
  }
}
```
locationのプロパティまとめ

```js:js
//プロパティ（すべて代入して変更可能です）
location.href;		//例: "http://uhyohyo.net/javascript/12_3.html?key=value#abc"
location.protocol;	//例: "http:"
location.host;		//例: "uhyohyo.net"
location.hostname;		//例: "uhyohyo.net"
location.port;		//例: ""
location.pathname;	//例: "/javascript/12_3.html"
location.search;	//例: "?key=value"
location.hash;		//例: "#abc"
```



###より詳細なページ遷移

先程のpushStateのときに、第一引数にnullを入れていました。
ここにはなにがはいるのでしょうか？

じつは「遷移元のURL」や「ツリーの開閉状態」など、データの情報を格納することができます。
このデータを利用して、遷移元へ戻るなどの動作を加えることができます。

```js:js
const state = {
 prev_title:document.title,
 prev_url:location.pathname;
}

history.pushState(state, 'ページのタイトル', '/search/foo');

//このstateアクセスするには
window.onpopstate=function(e)
       console.log(e.state);
}

//もしくは
history.state
```

##アプリケーションキャッシュ   
 - スマートフォン対応が必須になってきた時代tで、考慮すべきは通信回線の貧弱さである
 - キャッシュマニフェストやApplicationCacheAPIなどを利用することで従来はブラウザ任せであったキャッシュファイルの管理を開発者側ですることができるようになる


**現在では非推奨になっているので、service workerなどを参照する。**

<br>
<br>
###キャッシュマニフェスト
キャッシュマニフェストとは、キャッシュのルールを記述した単なるテキストファイルのこと。キャッシュするファイルとしないファイルを分けることができる。



####キャッシュマニフェスト作成手順
######1.htmlタグのmanifest属性にキャッシュのパスを記載（このとき拡張子は決まりは無いが.appcacheを推奨）

```html:html
<!doctype html>
<html lang="ja" manifest="sample.appcache">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link rel="stylesheet" href="style.css">
  <script src="index.js"></script>
  <title>Document</title>
</head>
<body>
<img src="sample.png" alt="">
</body>
</html>
```

######2.同ディレクトリにhtaccessという名前のファイルを作成。AddTypeディレクティブで、「AddType」「text/cache-manifest」「.appcache」を記述する

```:htaccess
AddType text/cache-manifest .appcache
```

######3.sample.appcacheファイルに　CACHE MANIFESTと、CACHEするファイルを書く。

```:sample.appcache
CACHE MANIFEST
#revison 1

//現在読み込まれているファイルは、CSS、JS、pngファイルの3つ
CACHE:
./index.js
./style.css
./sample.png
```

<br>

####キャッシュファイルの更新
キャッシュに登録されたページを開くとき、ブラウザの読み込み順に注意する必要がある。読み込み順は以下の通り。
***
1. キャッシュされたファイルを参照してページを読み込む
2. 裏で自動的にキャッシュマニフェストの更新を確認する
3. 更新されていれば全てのファイルを自動的にキャッシュし直す
4. 次回のアクセスから、更新されたファイルを参照する。

***
つまり、ファイルを更新しても最初の読み込みでは、古いバージョンのキャッシュが読み込まれ、2回目以降から更新されたフファイルが読み込まれる。また、ファイルの更新はキャシュマニフェストの更新で決まるので、読み込みファイルのルール変更がなくても更新する必要がある。


```:sample.appcache
CACHE MANIFEST
#revison 2

//現在読み込まれているファイルは、CSS、JS、pngファイルの3つ
CACHE:
./index.js
./style.css
./sample.png
```

####Networkセクション

Networkセクションに記述されたリソースはキャッシュされず、常にネットワーク経由でアクセスされる。

```:sample.appcache
CACHE MANIFEST
#revison 2

//現在読み込まれているファイルは、CSS、JS、pngファイルの3つ
CACHE:
./index.js
./style.css
./sample.png

NETWORK:
/api/
```

またキャッシュマニフェストを利用したアプリケーションでは外部ドメインのリソースはNETWORKセクションに記述されたリソースのみがアクセス可能になる。APIなどを利用する場合は、明示的にホワイトリスト指定する必要がある。

```:sample.appcache
NETWORK:
http://search/yahooapis.jp/
```

####FALLBACKセクション
あるリソースにアクセスできなかった場合の、だいたいリソースを指定する

```:sample.appcache
FALLBACK:
contents/   notfound.html
```