【Barba.js版】高速かつスムーズなページ遷移を実現する pjax 覚書

2年くらい前に書いた「[高速かつスムーズなページ遷移を実現する pjax 覚書](https://qiita.com/kokushin/items/f0a7066ff644036cba5e)」に直近でも「いいね！」が付くので、もうちょっとイマドキな実装方法に書き直してみようと思います。

今回ご紹介するライブラリは__「Barba.js」__というもので、「Pjax」を簡単に実装できるライブラリの一つになります。

[Barba.js 公式サイト](http://barbajs.org/)

こういった感じのサイトが作れます。

[Circles Demo](http://barbajs.org/demo/nextprev-circle/index.html)

アイディア次第では、面白い見せ方ができそうですね。

これからWebサイトにシームレスなページ遷移演出を実装したいと考えている方は是非参考にしてみてください。


## 演出実装の基本

この「Barba.js」を導入することで、「Ajax+PushState」という基本的なPjaxの機能が実装できるほか、APIが充実しており「リンクのクリック直後」や「ページの読み込み前」、「ページの読み込み完了後」などの状態を簡単に取得できるようになります。
この状態に応じてJSでクラス追加/削除処理を書き、CSSでアニメーションさせるのがベターな実装方法かなと思います。

## 導入方法

詳しくは公式サイトに書かれているとおりですので、ざっくりと説明します。

[Barba.js - Installation](http://barbajs.org/installation.html)

インストールはnpmやCDNなどを使いましょう。
もちろん普通にダウンロードしても動きます。

```
npm install barba.js --save-dev
```

```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/barba.js/1.0.0/barba.min.js"></script>
```

非同期で読み込ませたい親要素に `id="barba-wrapper"` を付与し、その直下の子要素に `class="barba-container"` を付与します。
※Pjaxが適用されるすべてのページに記述します。

```html
<div id="barba-wrapper">
  <div class="barba-container">
    <!-- ここに非同期で読み込ませたい内容を記述 -->
  </div>
</div>
```

あとはJS側でBarba.jsを実行すれば導入完了です。

```js
Barba.Pjax.start();
```

## イベントを取得してみる

Barba.jsには以下のようなイベントが存在します。

| イベント名 | 引数 | 発火タイミング |
|:--|:--|:--|
| linkClicked | HTMLElement, MouseEvent | ユーザーがpjaxが設定されたリンクをクリックしたとき |
| initStateChange | currentStatus | リンクが変更されたとき |
| newPageReady | currentStatus, prevStatus, HTMLElementContainer, newPageRawHTML | 新しい要素が読み込まれ、コンテナ要素に挿入されたとき |
| transitionCompleted | currentStatus[, prevStatus] | 遷移処理が完了し、以前の要素が削除されたとき |

これらのイベントをリスナに登録するには、以下のBarba.js専用のメソッドを利用します。

```js
Barba.Dispatcher.on('イベント名', () => {
  // ここに処理を書く
});
```

例えば次の例では、「リンクをクリックしたときに `body` に `is-transition-start` クラスを追加する」という処理になります。

```js
Barba.Dispatcher.on('linkClicked', (HTMLElement, MouseEvent) => {
  document.body.classList.add('is-transition-start');
});
```

## ページごとに処理を変えたい場合

例えばmetaタグの動的変更など、ページごとに個別でJSを発火させたい場合は、`newPageReady` イベントで取得できる引数 `currentStatus` 内の `namespace` 値を取得して条件分岐させる方法があります。

`namespace` は、各ページの `barba-container` クラスに `data-namespace="任意の名前空間"` として記述しておくことで利用できるようになります。

TOPページだけ任意のJSを実行したいときは、下記のように書きます。

```html
<div class="barba-container" data-namespace="top">
```

```js
Barba.Dispatcher.on('newPageReady', (currentStatus, oldStatus, container) => {
    switch (currentStatus.namespace) {
    case 'top':
        // data-namespace="top"のときに実行させたい処理
        console.log('topで実行されました');
        break;
    ...
});
```

この方法でもよいのですが、Barba.jsのヘルパー機能として提供されている「Views」を使うともっと効率的に書くことが可能です。

[Barba.js - Views](http://barbajs.org/views.html)

上記と同じ処理をViewsで書くと...

```js
const Top = Barba.BaseView.extend({
    namespace: 'top',
    onEnterCompleted: () => {
        // 準備されたコンテナへの遷移が完了したときに実行される
        console.log('topで実行されました');
    },
});

Top.init();
```

簡潔に書くことができました。
上記はTOPページのみの処理ですが、他のページ分も同様に関数を追加していけば良いです。

また、`onEnter, onEnterCompleted, onLeave, onLeaveCompleted` など遷移状態に応じて処理を分岐させることも可能です。

## 遷移アニメーションをつけたデモ

下記ページにて用意しました。

https://kokushin.github.io/barbajs-qiita/index.html

今まで紹介したイベントやViewsなどを使っています。
また、軽い遷移アニメーションもつけてみました。

`linkClicked` イベントと `transitionCompleted` イベントを利用し、クラスを追加/削除しているだけです。
あとはCSSアニメーションの作り込み次第で超イケてるサイトが作れるかと思います！

[ソースコードはこちら](https://github.com/kokushin/barbajs-qiita/)

## リンクをクリックしたときにPjax遷移をさせたくない場合

デフォルトだと `target="_blank"` を除くすべてのリンクにPjaxイベントが適用されてしまいます。

遷移させたくないリンクに関しては、`no-barba` クラスをaタグに付与すれば良いです。

`Barba.Pjax.preventCheck` メソッドを拡張することでも対応できるっぽいです。
詳しくはこちらのページに書かれていますのでチェックしてみてください。

[Is it possible to ignore barba.js on some links?](http://barbajs.org/faq.html)

## あとがき

SPAなどが流行ってPjaxは古い技術...と思われがちですが、導入コストの低さからWebサイト制作界隈においてはまだまだ使える技術だと思っています。

Webサイトに一工夫したいときや体感速度を向上させたいときなどに是非導入をご検討ください。