ブラウザ関連のJavaScript

ユーザー情報の取得については、こちらをご参照ください。
[JavaScriptによるユーザー情報の取得](https://qiita.com/takeshisakuma/items/8c4efdcb1ba52f5e4ae9)




## ページ表示時に処理

|イベント|内容|
|---|---|
|DOMContentLoaded|HTMLドキュメント解析完了時(deferを指定しているなら不要)|
|load|全リソースの読み込み完了時(キャッシュの場合は対象外)|
|pageshow|全リソースの読み込み完了時(キャッシュの場合も対象)|

```:js
window.addEventListener("load", () => {
  console.log("ページが読み込まれた");
});
```

## ページ非表示時に処理

|イベント|内容|
|---|---|
|beforeunload|ページ遷移直前|
|unload|ウィンドウを閉じた時、他のページに切り替えた時、ページをリローした時に発生(キャッシュの場合は対象外)|
|pagehide|ページ遷移などで元のページが隠れた時|

```:js
window.addEventListener("beforeunload", () => {
  event.returnValue;
});
```






## タブがバックグラウンドになったときに処理

|イベント|内容|
|---|---|
|visibilitychange|タブのコンテンツが表示されたとき、非表示(バックグラウンド)になったとき|


document要素に対して設定します。
document.visibilityStateと組み合わせて使います。

```:js
document.addEventListener('visibilitychange', () => {

  if (document.visibilityState === 'visible') {
    console.log("コンテンツが表示された");
  }

  if (document.visibilityState === 'hidden') {
    console.log("コンテンツがバックグラウンドになった");
  }

})
```











## ページのフォーカスのイベント
### ページにフォーカスされた時

```:JavaScript
window.addEventListener("focus", () => {
  console.log("ページにフォーカスされた");
});
```

### ページからフォーカスが外れた時

```:JavaScript
window.addEventListener("blur", () => {
  console.log("ページからフォーカスが外れた");
});
```





## タイトル
### タイトルの取得

```:html
<button id="js-getTitleButton">タイトル取得</button>
```

```:JavaScript
const getTitleButton = document.getElementById("js-getTitleButton");
        
getTitleButton.addEventListener("click", () => {
  console.log(document.title);
});
```

### タイトルの変更

```:html
<button id="js-changeTitleButton">タイトル変更</button>
```

```:JavaScript
const changeTitleButton = document.getElementById("js-changeTitleButton");

changeTitleButton.addEventListener("click", () => {
  document.title = "new title"
});
```





## ハッシュ
### 値の取得

```:htm
<button id="js-getHashButton">ハッシュ取得</button>
```
```:JavaScript
const getHashButton = document.getElementById("js-getHashButton");
 
getHashButton.addEventListener("click", () => {
  console.log(location.hash);
});
```

### 変更イベント

```:html
<button id="js-changeHashButton">ハッシュ変更</button>
```

```:JavaScript
const changeHashButton = document.getElementById("js-changeHashButton");
 
//ハッシュ変更        
changeHashButton.addEventListener("click", () => {
  location.hash = "sample";
});
 
//ハッシュ変更監視
window.addEventListener("hashchange", () => {
  console.log("ハッシュが変更された");
});
```




## ダイアログ
### アラート

```:html
<button id="js-alertButton">アラート</button>
```

```:JavaScript
const alertButton = document.getElementById("js-alertButton");

alertButton.addEventListener("click", () => {
  alert("アラート");
});
```

### コンファーム

```:html
<button id="js-confirmButton">コンファーム</button>
```

```:JavaScript
const confirmButton = document.getElementById("js-confirmButton");

confirmButton.addEventListener("click", () => {
 
  const confirmReaction = confirm("OK or Cancel");
   
  if (confirmReaction === true) {
    console.log("OKを選択した");
  }
   
  if (confirmReaction === false) {
    console.log("Cancelを選択した");
  }
   
});
```

### 文字入力プロンプト

```:html
<button id="js-promptButton">プロンプト</button>
```

```:JavaScript
const promptButton = document.getElementById("js-promptButton");
promptButton.addEventListener("click", () => {
  const promptReaction = prompt("文字入力してください", "デフォルト文字列")

  if (promptReaction === "") {
    console.log("入力されなかった");
  } else if (promptReaction == null) {
    console.log("キャンセルされた");
  } else {
    console.log(`${promptReaction}と入力された`);
  }
  
});
```







## ウィンドウサイズ

|プロパティ||
|---|---|
|window.innerWidth|ビューポートの幅|
|window.innerHeight|ビューポートの高さ|
|window.document.documentElement.clientWidth|(スクロールバーを除く)|
|window.document.documentElement.clientHeight|(スクロールバーを除く)|


```:html
<button id="js-windowSizeButton">ウィンドウサイズ</button>
```

```:JavaScript
const windowSizeButton = document.getElementById("js-windowSizeButton");
 
windowSizeButton.addEventListener("click", () => {
 
  console.log(`幅${window.innerWidth}px`);
  console.log(`高さ${window.innerHeight}px`);
 
});
```

## スクロール
### 表示位置の取得
ドキュメント左上基準で取得されます。

|プロパティ|内容|
|---|---|
|window.scrollX|X軸方向のスクロール量|
|window.scrollY|Y軸方向のスクロール量|

```:html
<button id="js-scrollPositionButton" style="margin-top:2000px;">スクロール位置取得</button>
```

```:JavaScript
const scrollPositionButton = document.getElementById("js-scrollPositionButton");
 
scrollPositionButton.addEventListener("click", () => {
  console.log(`X軸${window.scrollX}`);
  console.log(`Y軸${window.scrollY}`);
});
```

### 表示位置の変更



|メソッド|内容|
|---|---|
|scrollTo(X,Y)|スクロールする座標の指定(絶対)|
|scrollBy(X,Y)|スクロールする座標の指定(相対)|

```:html
<button id="js-scrollButton" style="margin-top:2000px;">スクロールボタン</button>
```

```:JavaScript
const scrollButton = document.getElementById("js-scrollButton");
 
scrollButton.addEventListener("click", () => {
  window.scrollTo(0, 0);
});
```



### スクロール時に処理

|イベント|内容|
|---|---|
|scroll|対象の要素がスクロールしたとき|



```:js
window.addEventListener('scroll',()=>{
  console.log(window.scrollX,window.scrollY);
});
```

## Intersection Observer

「基準の要素」と「監視される要素」を監視して、重なり具合をきっかけにして処理を行います。

### IntersectionObserver オブジェクトの作成

```:js
const observer = new IntersectionObserver(callback, options);
```

#### IntersectionObserverの第一引数
交差割合が変わったときに実行されるコールバック関数です。

```:js
const callback = (entries, observer) => {
  entries.forEach(entry => {
    //処理
  })
}
```

|引数|説明|
|---|---|
|entries|交差オブジェクト<br>observe メソッドを複数回呼び出せば複数の要素を監視できるので配列<br>このオブジェクトから交差の割合などの情報を引き出せる|
|observer|IntersectionObserverオブジェクト|






#### IntersectionObserverの第二引数
オプションです。

```:js
 const options = {
   root: null,
   rootMargin: 0,
   threshold: [0.25, 0.5]
 }
```

|項目|説明|
|---|---|
|root|基準にしたい要素を指定<br>デフォルトはビューポート|
|rootMargin|対象要素との交差位置の調整<br>正の値を指定：画面に入る前に交差判定<br>デフォルト：0|
|threshold|コールバックを実行する交差の閾値<br>数値か、複数の場合は配列で指定可能<br>例：threshold: [0.2, 0.5]の場合は、20%と50％のときに判定が行われる<br>範囲：0～1の間(デフォルト0)|




### observerのobserveメソッドで監視を開始

```:js
const target = document.querySelector('#something');
observer.observe(target)
``` 

|IntersectionObserverEntryのプロパティ|内容|
|---|---|
|intersectionRatio|交差している領域の割合|
|boundingClientRect|監視対象の要素のサイズと、そのビューポートに対する位置|
|intersectionRect|交差している領域のサイズと、そのビューポートに対する位置|
|isIntersecting|trueは交差状態への移行、falseは非交差状態への移行|
|rootBounds|rootの要素のサイズと、そのビューポートに対する位置|
|target|監視対象|
|time|タイムスタンプ|


```:html
<div class="greenSection"></div>
 
<div class="redSection"></div>
 
<div class="yellowSection"></div>
 
<div class="greenSection"></div>
 
<div class="redSection"></div>
 
<div class=" yellowSection"></div>
```

```:css
.greenSection {
  background-color: green;
  height: 1000px;
}

.redSection {
  background-color: red;
  transition: background-color 0.4s ease-out;
  height: 2000px;
}

.redSection.active {
  background-color: blue;
}

.yellowSection {
  background-color: yellow;
  height: 1000px;
}
``` 

```:js
//Intersection Observerの処理
const startIntersectionObserver = () => {

  //thresholdで指定した値の時に呼ばれるコールバック
  const callback = (entries, observer) => {
    entries.forEach(entry => {

      //交差判定の時点でintersectionRationが20%以上のとき
      if (entry.intersectionRatio >= 0.2) {

        //activeクラスを追加
        entry.target.classList.add('active')
      }

      //交差判定の時点で見えている領域が20%を下回ったとき
      else if (!entry.isIntersecting) {
        //activeクラスを削除
        entry.target.classList.remove('active')
      }
    })
  }

  //Intersection Observerのオプションの指定
  const option = {

    //基準となる要素の指定(ブラウザ)
    root: null,

    //対象要素との交差位置の調整
    rootMargin: "0px",

    //20%と100%で交差判定を出す
    threshold: [0.2, 1]

    }

  //Intersection Observerのインスタンス生成
  const observer = new IntersectionObserver(callback, option);

  //対象の要素取得(NodeList)
  const targetList = document.querySelectorAll('.redSection');
  //NodeListの配列化
  const targetArray = [...targetList];

  //対象の配列の各要素を監視する
  targetArray.forEach((target) => {
    observer.observe(target);
  })

}
 
//Intersection Observerの処理の実行
startIntersectionObserver()
``` 







## リサイズ
### 画面サイズ変更時に処理
スマホはスクロール時にアドレスバーが非表示になったり意図しないリサイズイベントが起こるので注意が必要です。

|イベント|内容|
|---|---|
|resize|ブラウザのウインドウサイズが変わった時|

```:js
window.addEventListener('resize', () => {
  console.log('ブラウザがリサイズされた');
})
``` 

### 負荷削減(リサイズ時の処理削減)
サイズが1ピクセルでも変わると発火するので負荷が高いです。
リサイズの1秒後に処理を行うタイマー+リサイズごとに解除することで負荷を抑えます。

```:js
let resizeTimer;
 
window.addEventListener('resize', () => {
 
  //リサイズタイマーに値があればタイマー解除
  if (resizeTimer != null) {
    clearTimeout(resizeTimer);
  }
 
  const onResize = () => {
    console.log("リサイズした")
  }
 
  resizeTimer = setTimeout(() => {
    onResize();
  }, 1000);
 
})
```

### window.matchMedia

|違い|内容|
|---|---|
|resizeイベント|ウィンドウサイズ変更ごとに実行される|
|matchMedia()|一度だけ実行される(負荷軽減)|


|メソッド|内容|
|---|---|
|matchMedia(メディアクエリ)|メディアクエリの情報|
|matchMedia(メディアクエリ).addListener(処理)|メディアクエリに一致したとき処理を実行|



|プロパティ|内容|
|---|---|
|matchMedia(メディアクエリ).match|メディアクエリに一致するかどうか(真偽値)|
 	

```:js
const mediaQueryList = matchMedia('(min-width:500px)');
console.log(mediaQueryList);　//幅が500以上のときtrue
``` 

```:js
matchMedia('(max-width:300px)').matches; //真偽値
matchMedia('(min-width:100px) and (max-width:700px)').matches; //真偽値
```

#### スマホ、タブレット、PCの3段階の例

```:js
document.addEventListener('DOMContentLoaded', () => {

  //スマホとタブレットの境界780px
  const mqSp2Tab = window.matchMedia('screen and (max-width: 780px)');

  //タブレットとPCの境界1280px
  const mqTab2Pc = window.matchMedia('screen and (max-width: 1280px)');

  //スマホとタブレットのブレイクポイントを通過したらイベント発火する機能
  const checkSp2Tab = (mqSp2Tab) => {
    if (mqSp2Tab.matches) {
      console.log("タブ→スマホ");
      } else {
      console.log("スマホ→タブ");
      }
    }

  //タブレットとPCのブレイクポイントを通過したらイベント発火する機能
  const checkTab2Pc = (mqTab2Pc) => {
  if (mqTab2Pc.matches) {
    console.log("PC→タブ");
    } else {
    console.log("タブ→PC");
    }
  }

  //ブレイクポイント通過したら発火する機能をイベントリスナーに追加
  mqSp2Tab.addListener(checkSp2Tab);
  mqTab2Pc.addListener(checkTab2Pc);

});
```

端末の縦横の向きの変更(縦横比どちらが長いかだけで判定)を感知して発火

```:js
document.addEventListener('DOMContentLoaded', () => {

  const mqRotation = window.matchMedia('(orientation: portrait)');

  //縦横のどちらが長いかが変わった時にイベント発火する機能
  const orientationChange = (mqRotation) => {
    if (mqRotation.matches) {
      console.log("横長→縦長");
    } else {
      console.log("縦長→横長");
    }
  }

  //縦横のどちらが長いかが変わった時にイベント発火する機能をイベントリスナーに追加
  mqRotation.addListener(orientationChange);

});
```





## ResizeObserver
指定した監視要素のリサイズを検知して処理を行う事ができます。


### observerの作成

```:js
const resizeObserver = new ResizeObserver(entries => {
  for (const entry of entries) { ... }
}); 
```

### 対象の監視開始

```:js
resizeObserver.observe(target);
```

### 対象の監視終了

```:js
resizeObserver.unobserve(target);
```

### サンプル

```:html
<p id="text--red">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquam, autem optio qui molestias accusamus fugiat nam debitis sunt modi! Voluptatum ullam minus eius earum voluptate dicta dolore neque, voluptatibus itaque maiores hic necessitatibus debitis repudiandae! Quaerat voluptatibus velit magnam veritatis, adipisci perspiciatis reprehenderit consectetur magni laboriosam, dolore repellendus doloribus nesciunt, est dolorum dignissimos. Earum, aliquam nulla? Dolor quo ipsum omnis neque obcaecati corporis sint. Libero repellendus sed autem optio quia doloribus fugiat veritatis excepturi, molestias deserunt nam facere. Quibusdam amet distinctio officia suscipit labore magnam obcaecati aperiam dolorem beatae impedit vitae optio nostrum alias voluptas repellendus similique ad corrupti commodi libero temporibus, excepturi quam. Vero ducimus nisi eaque doloremque atque facilis, tempora accusantium rerum nesciunt, aliquid asperiores ad in pariatur saepe, doloribus deleniti culpa repellendus ratione quia quisquam deserunt iste enim? Nulla, omnis. Maxime cupiditate, delectus corporis praesentium aut commodi architecto eius eos, animi odio dolore fuga totam sint. Suscipit dolorem culpa voluptatem dolor sint. Dignissimos aliquid obcaecati nemo nesciunt eos sint accusamus quos, odit neque architecto aliquam natus magni a nisi libero, omnis quas impedit voluptate! Obcaecati ducimus atque reiciendis, mollitia sint eligendi labore impedit voluptates laboriosam dolor debitis veritatis saepe amet accusamus cupiditate eum dolorem magni nulla. Esse, voluptate, dolorem inventore mollitia delectus tenetur deleniti quibusdam ducimus perspiciatis consequuntur fuga consectetur rerum itaque laboriosam nisi a maxime rem reprehenderit, qui hic enim nihil accusamus soluta! Sapiente veritatis eos obcaecati, accusamus reiciendis delectus voluptates natus odit dolor excepturi officiis iure? Saepe in tenetur soluta libero? Nam, iusto quisquam. Reiciendis, blanditiis dolor? Unde mollitia perferendis aliquid expedita sapiente, ipsa harum possimus debitis numquam exercitationem ipsam suscipit nemo porro hic dolor dolorem adipisci laudantium voluptatem fugit aliquam, tenetur voluptatibus maxime inventore! Sequi magni ad, veritatis, voluptatem aliquid dolorum mollitia laudantium libero commodi ipsam ullam porro doloremque fugit in hic quasi ut.
</p>

<p id="text--blue">
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Hic, officiis nobis dolorum sint asperiores a aperiam velit fugit aliquid nihil sunt ducimus nostrum! Quas assumenda, corporis rerum molestiae in culpa! Neque dolores at consectetur nisi inventore dolorem corrupti quibusdam maxime unde eos! Ipsam asperiores consectetur unde commodi tempora sit magni ea nesciunt modi explicabo quo voluptas, provident reiciendis. Eligendi deleniti at officia excepturi nemo quae doloribus itaque, reiciendis, explicabo velit rem et cum. Laudantium pariatur doloribus ab delectus qui perspiciatis alias blanditiis vero voluptate quam dicta culpa incidunt quae illo, cupiditate praesentium fugit quia tenetur fugiat iusto ipsa nisi consequuntur. Doloribus quisquam amet fuga? At ab magnam inventore architecto nostrum explicabo quasi labore sit illum delectus, mollitia voluptatum quibusdam temporibus commodi rerum placeat? Vel quidem recusandae ipsum asperiores ratione odit porro repudiandae reiciendis doloribus ad, corporis illo est animi iste natus! Odit similique reiciendis id temporibus molestiae libero est iste, quibusdam ea! Atque, dolores? Atque minima impedit dolores nobis dolorem exercitationem officia harum? Ullam voluptatum modi sint. Voluptas numquam saepe officiis hic dolore nisi doloremque consectetur quidem, voluptatem unde ad alias vitae modi labore aut quia sit ipsa fugit perferendis inventore praesentium repellendus! Atque culpa sapiente laboriosam labore tenetur molestias velit, explicabo minima temporibus ab ad assumenda repudiandae ipsum totam aspernatur iure iste modi, amet, sint ratione placeat sed dolorum dicta. Illum magnam veniam accusantium nulla unde non esse, provident perspiciatis commodi dolorem minima doloribus fugit nihil ut qui similique laboriosam culpa earum dicta at fuga voluptas quo porro. Odio laboriosam illum, obcaecati quo aliquam hic eligendi fugit repellat earum veniam saepe iste quidem cum facilis. Saepe qui obcaecati nisi sapiente porro dolore molestias tenetur expedita explicabo, modi recusandae eos necessitatibus ipsam deleniti odit ut distinctio doloremque numquam dicta reiciendis, debitis dolorum adipisci est odio. Incidunt fugiat illo porro asperiores.
</p>

<p id="text--yellow">
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Modi corporis quisquam quidem, nobis laboriosam, quasi optio delectus autem tempora accusantium eligendi, placeat magni mollitia illum est tenetur accusamus dolorem nemo! Reprehenderit, doloremque. Quos, officia corrupti fugiat nulla illum iusto accusantium ex nam necessitatibus esse dolor veniam excepturi id accusamus error impedit sed sunt quidem inventore adipisci optio quaerat rerum! Mollitia perferendis quibusdam sed impedit quo aut facere nemo quaerat odit ut pariatur cumque nulla molestiae fugiat, sunt quasi suscipit omnis consequuntur quia eligendi eaque architecto fuga maiores? Facilis dolores libero magni nam sed assumenda minus accusantium, placeat, vero aliquam inventore consequatur eligendi totam blanditiis error natus quos excepturi necessitatibus porro repellat, aspernatur soluta. Illum a, nesciunt incidunt expedita excepturi cumque autem nobis placeat impedit deleniti fugit. Optio distinctio natus dolor voluptates quaerat atque reiciendis a sit, molestiae itaque quo, sequi assumenda, quis aliquam? Nobis velit beatae magni doloremque accusamus eos aperiam quaerat amet, suscipit, error quos, culpa quod eum sunt soluta. Aspernatur repellendus eum nam eligendi, maxime repudiandae similique accusamus amet earum facilis quod explicabo fugit totam praesentium pariatur suscipit, quibusdam aperiam omnis labore adipisci sequi dolore ducimus perspiciatis! Unde explicabo vel cumque impedit recusandae. Corrupti, repellendus exercitationem? Natus iure facilis, id delectus veniam autem enim reiciendis quod voluptas, illo minima repudiandae alias dolores voluptates accusantium? Veritatis, praesentium atque? Aliquid at atque dolores quaerat, consequuntur laboriosam quae maxime maiores consectetur, quibusdam inventore beatae porro corporis fuga in ipsam mollitia velit voluptatum nisi praesentium? Consequuntur error aliquam temporibus, fugit assumenda minima aspernatur, amet natus ipsa perspiciatis aperiam sapiente voluptate incidunt atque itaque alias voluptas et neque, sit consequatur autem! Culpa dolor facere architecto consectetur nulla unde ea obcaecati dolorem neque quia sapiente provident voluptate soluta minus, eaque aperiam nihil totam sunt quas inventore adipisci debitis! Quos expedita nulla fugit tempore optio!
</p>
```

```:css
#text--red {
   background-color: red;
}
 
#text--blue {
  background-color: blue;
  max-width: 800px;
}
 
#text--yellow {
  background-color: yellow;
  max-width: 400px;
}
```

```:js

//監視対象の取得
const red = document.querySelector("#text--red");
const blue = document.querySelector("#text--blue");
const yellow = document.querySelector("#text--yellow");

const resizeObserver = new ResizeObserver(entries => {
  for (const entry of entries) {
                
    //リサイズされた検知した要素
    console.log("リサイズされた要素：" + entry.target.id);

    //位置、サイズ
    console.log("top：" + entry.contentRect.top);
    console.log("left：" + entry.contentRect.left);
    console.log("width：" + entry.contentRect.width);
    console.log("height：" + entry.contentRect.height);

  }

});

resizeObserver.observe(red);
resizeObserver.observe(blue);
resizeObserver.observe(yellow);
```

## フルスクリーン表示

```:html
<button id="js-fullscreenButton">フルスクリーン</button>
<button id="js-clearfullscreenButton">フルスクリーン解除</button>
```

```:JavaScript
const fullscreenButton = document.getElementById("js-fullscreenButton");

fullscreenButton.addEventListener("click", (element) => {

  //chrome.firefox
  if (document.body.requestFullscreen) {
    document.body.requestFullscreen();
  }
 
  //edge
  if (document.body.webkitRequestFullscreen) {
    document.body.webkitRequestFullscreen();
  }
 
});
 
const clearfullscreenButton = document.getElementById("js-clearfullscreenButton");
 
clearfullscreenButton.addEventListener("click", () => {
             
  //chrome,firefox
  if (document.exitFullscreen) {
    document.exitFullscreen();
  }
   
  //edge
  if (document.webkitExitFullscreen) {
    document.webkitExitFullscreen();
  }
});
```












## ページ遷移

### ページを移動

```:html
<button id="js-movePageButton">ページ移動</button>
```

```:JavaScript
const movePageButton = document.getElementById("js-movePageButton");

movePageButton.addEventListener("click", () => {
  location.href = "https://www.google.co.jp/";
});
```

### ページをリロード

```:html
<button id="js-reloadPageButton">ページリロード</button>
```

```:JavaScript
const reloadPageButton = document.getElementById("js-reloadPageButton");

reloadPageButton.addEventListener("click", () => {
 
  //キャッシュを使ったリロード
  location.reload();
 
  //キャッシュを使わないリロード
  location.reload(true);
             
});   
```  

### 別ウィンドウを開く

```:html
<button id="js-openNewWindowButton">別ウィンドウを開く</button>
```

```:JavaScript
const openNewWindowButton = document.getElementById("js-openNewWindowButton");

openNewWindowButton.addEventListener("click", () => {
  window.open("https://www.google.co.jp");
});
```
## 履歴
### 履歴の前後のページに移動
|メソッド|内容|
|---|---|
|history.back()|履歴1つ戻る|
|history.forward()|履歴1つ進む|
|history.go(n)|履歴nつ進む|

```:html
<button id="js-historygoMinus2Button">履歴2つ戻る</button>
<button id="js-historyBackButton">履歴1つ戻る</button>
<button id="js-historyforwardButton">履歴1つ進む</button>
<button id="js-historygo2Button">履歴2つ進む</button>
```

```:JavaScript
const historygoMinus2Button = document.getElementById("js-historygoMinus2Button");
const historyBackButton = document.getElementById("js-historyBackButton");
const historyforwardButton = document.getElementById("js-historyforwardButton");
const historygo2Button = document.getElementById("js-historygo2Button");

historygoMinus2Button.addEventListener("click", () => {
  history.go(-2);
});

historyBackButton.addEventListener("click", () => {
  history.back();
});

historyforwardButton.addEventListener("click", () => {
  history.forward();
});

historygo2Button.addEventListener("click", () => {
  history.go(2);
});
```

### 履歴の操作
URLが変わるだけで、ページの内容は変わりません。
実際にそのページに遷移する場合は読み込み処理を書く必要があります。

```:html
const historyPushButton = document.getElementById("js-historyPushButton");
const historyReplaceButton = document.getElementById("js-historyReplaceButton");
const historyBackButton = document.getElementById("js-historyBackButton");
const historyforwardButton = document.getElementById("js-historyforwardButton");
```

```:JavaScript
const historyPushButton = document.getElementById("js-historyPushButton");
const historyReplaceButton = document.getElementById("js-historyReplaceButton");
const historyBackButton = document.getElementById("js-historyBackButton");
const historyforwardButton = document.getElementById("js-historyforwardButton");

historyPushButton.addEventListener("click", () => {
  history.pushState(null, null, "/nextpage.html");
  console.log("履歴が追加された");
});

historyReplaceButton.addEventListener("click", () => {
  history.replaceState(null, null, "/other.html");
  console.log("履歴が上書きされた");
});

historyBackButton.addEventListener("click", () => {
  history.back();
});

historyforwardButton.addEventListener("click", () => {
  history.forward();
});

window.addEventListener("popstate", () => {
  console.log("履歴が辿られた");
})
```