
こんにちはCTOの奥田です。
 先日から関西のクリエイターユニットで配信をはじめました。その名も「NOT4H」
自粛中はZoomから配信していたのですが6月からは「ハコウマ」というスタジオをお借りして配信しています。
 毎週木曜日20:00からTwitterにて配信してますのでよろしければ御覧ください。
さて、今回はBarba.jsのVersion2についてご紹介いたします。
 前回のブログでご紹介したVersion1からさらに進化して使いやすくなっております。
 今回はページ遷移の簡単なDEMOも用意しておりますので併せてご確認ください。
Table of contents
Barba.js v2とは
Barba.jsとは非同期でページ遷移をさせることができるJavaScriptのライブラリです。
 非常に軽量なライブラリでv1の頃から弊社の案件のほとんどで使用させていただいています。
Barba.jsは、小さくて(7kbに圧縮された)使いやすいライブラリで、Webサイトのページ間をスムーズに移行するのに役立ちます。これは、WebサイトをSPA (単一ページアプリケーション)のように実行し、ページ間の遅延を減らし、ブラウザーのHTTPリクエストを最小限に抑え、ユーザーのWebエクスペリエンスを向上させます。
インストール
まずはインストール方法です。
 npmやyarnでインストールしimportするか、CDNでscriptを読み込んでください。
npm install @barba/core --save
yarn add @barba/core
import barba from '@barba/core';
barba.init({
  // ...
});
<!-- unpkg --> <script src="https://unpkg.com/@barba/core"></script> <!-- jsdelivr --> <script src="https://cdn.jsdelivr.net/npm/@barba/core"></script>
<script>
    barba.init({
        // ...
    })
</script>また、モダンブラウザであれば動作するようですが、以下のスクリプトをサポートしていないブラウザはPolyfillが必要です。
- Promise
- Set() and Map()
- Array.prototype.find
- IntersectionObserver(@barba/prefetchで使用)
polyfill.ioであれば下記を読み込んでください。
<script src="https://polyfill.io/v3/polyfill.min.js?features=default%2CArray.prototype.find%2CIntersectionObserver" crossorigin="anonymous" defer></script>
使い方
使い方は従来のBarbaから少し変更になっています。
 デフォルトではラッパー要素にdata-barba属性wrapperを指定し、内包したdata-barba属性にcontainerを指定すると同ドメイン内のリンクをクリックした際に現在のページのcontainerが遷移先のcontainerと非同期で入れ替わります。
<body data-barba="wrapper">
    <main data-barba="container" data-barba-namespace="home">
    </main>
</body>パーシャルさせる要素は従来と同様、containerの外に配置することで書き換えられることはありません。
 namespaceは data-barba-namespace に変更されています。
Preventリンクの拡張
Barbaはデフォルトで非同期遷移させないリンクが指定されています。
 ただ、それだけでは補いきれないリンクも存在するのでBarba v1でも拡張させて使っていました。
 今回も同じく拡張しておきます。
const preventSettings = {
    // 外部リンクはtarget="_blank"に
    let site_url = location.protocol + '//' + location.host;
    if (!href.startsWith(site_url)) {
        el.setAttribute('target','_blank');
        return true;
    }
    // アンカーリンクであり同一ページでなければbarbaを有効に
    let url = location.protocol + '//' + location.host + location.pathname;
    let extract_hash = href.replace(/#.*$/,"");
    if (href.startsWith(location.protocol + '//' + location.host)) {
        if (href.indexOf('#') > -1 && extract_hash != url ){
            return false;
        }
    }
    // 拡張子が該当する場合はtarget="_blank"に
    if (/\.(xlsx?|docx?|pptx?|pdf|jpe?g|png|gif|svg)/.test(href.toLowerCase())) {
        el.setAttribute('target','_blank');
        return true;
    }
    // 該当クラスに属していればBarbaを無効に
    let ignoreClasses = ['ab-item'];
    ignoreClasses.forEach((cls) => {
        if (el.classList.contains(cls)) {
            return true;
        }
    })
}barba.init({
    prevent: preventSettings,
    ...
})head内の書き換え
従来のBarba同様head内の書き換えはtitleのみとなっています。
 こちらはプラグインを準備中のようなのでしばらくは自前のものを使いましょう。
const replaceHead = function(data){
    const head = document.head;
    const newPageRawHead = data.next.html.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0];
    const newPageHead = document.createElement('head');
    newPageHead.innerHTML = newPageRawHead;
    const removeHeadTags = [ 
        "meta[name='keywords']"
        ,"meta[name='description']"
        ,"meta[property^='og']"
        ,"meta[name^='twitter']"
        ,"meta[itemprop]"
        ,"link[itemprop]"
        ,"link[rel='prev']"
        ,"link[rel='next']"
        ,"link[rel='canonical']"
    ].join(',');
    
    const headTags = head.querySelectorAll(removeHeadTags)
    for(let i = 0; i < headTags.length; i++ ){
        head.removeChild(headTags[i]);
    }
    
    const newHeadTags = newPageHead.querySelectorAll(removeHeadTags)
    for(let i = 0; i < newHeadTags.length; i++ ){
        head.appendChild(newHeadTags[i]);
    }
}hookについては後の項目で説明しますがとりあえずbeforeEnterにhookしておけば良さそうです。
barba.hooks.beforeEnter((data) => {
    replaceHead(data);
})Google Analyticsに対応する
ページ遷移後にAnalyticsにトラッキングを送信する必要があります。
 analytics.jsの方式とgtag.jsの方式があるのでどちらも記載しておきます。
barba.hooks.after((data) => {
    if (typeof ga === 'function') {
        ga('set', 'page', window.location.pathname);
        ga('send', 'pageview');
    }
});gtag.jsはトラッキングIDが必要なので以下のようにgtag.js呼び出し時にwindow.GA_MEASUREMENT_IDにあらかじめ入れておいてください。
<script async src="https://www.googletagmanager.com/gtag/js?id={{UA-XXXXXXXX}}"></script>
<script>
    window.dataLayer = window.dataLayer || [];
    window.GA_MEASUREMENT_ID = "{{UA-XXXXXXXX}}"
    function gtag(){dataLayer.push(arguments);}
    gtag('js', new Date());
    gtag('config', window.GA_MEASUREMENT_ID);
</script>barba.hooks.after((data) => {
    if (typeof gtag === 'function') {
        gtag('config', window.GA_MEASUREMENT_ID,{
            page_path: window.location.pathname
        });
    }
});ページトランジション
ページトランジションはv1と大きく変更されています。
 トランジションの設定を複数指定することができ、それぞれのhookでasyncを使って完了を待ってから次のイベントへ移行させるということが可能です。
barba.init({
    transitions: [{
        name: 'default-transition',
        leave() {
            // create your stunning leave animation here
        },
        enter() {
            // create your amazing enter animation here
        }
    }]
});このあたりはそれぞれの表現の仕方によって様々なやり方があると思いますので割愛しますが、anime.jsを使った簡単なトランジションのデモを用意しておりますのでよろしければ学習に使ってください。
hookは初期読み込み時とページ遷移のそれぞれに用意されています。
 別のライブラリを併用したいときなどはこちらを参考に実行してください。
 onceがつくメソッドは初期読み込み時のみに実行されます。
| Name | Description | 
|---|---|
| beforeOnce | 読み込み前(初期読み込み時) | 
| once | 読み込み完了(初期読み込み時) | 
| afterOnce | 読み込み完了後(初期読み込み時) | 
| Name | Description | 
|---|---|
| before | ページ遷移の始まり | 
| beforeLeave | ページ遷移の前 | 
| leave | 現在のページの離脱 | 
| afterLeave | 現在のページの離脱後 (次ページコンテナがある状態) | 
| beforeEnter | 次ページに入る前 | 
| enter | 次ページに入った時 | 
| afterEnter | 次ページに入った後 | 
| after | すべて完了 | 
Viewごとのカスタマイズ
Viewによってトランジションをカスタマイズすることができます。
 対応しているhookがトランジションとは違いますので注意してください。
barba.init({
    views: [{
        namespace: 'index',
        beforeLeave(data) {
            // namespaceを`index`に設定したときのhook
        }
    }, {
        namespace: 'contact',
        beforeEnter(data) {
            // namespaceを`contact`に設定したときのhook
        }
    }]
});- beforeLeave
- afterLeave
- beforeEnter
- afterEnter
さいごに
今回はBarba.js v2についてご説明させていただきました。
 v1よりもわかりやすく汎用性まで考えられていて素晴らしいなと思いました。
 皆様も是非使ってみてください。
