サイトアイコン IT NEWS

Ajax(jQuery)とpushStateのみで実現するSPA用スクリプト

simple-jquery-spa

実際には「pjaxpushState + ajax)」というjQueryプラグインを使っていますが、今回はjQuerypushStateのみでSPAシングルページアプリケーション)を実装します。
以前紹介したCSSフレームワークRatchet」は、まさに今回の応用です。

JavaScriptライブラリを使わない理由

SPAと言えば、AngularReactの他、個人的に今後使いたいと思っているVueなどのJavaScriptライブラリがたくさんありますが、私のような面倒臭がりには大きな問題があります。

例えば、新しく覚えなければならないことが増えたり、フロントだけでなくサーバー側の処理やレスポンスを変えるなど、今まで作ったものを変更したりするのは真っ平ゴメンです!

今回紹介する方法を使えば、既存のWEBアプリに導入するだけで、SPAに変えることができます。

Ajaxでビューを返して抜き出す

以下の方法なら、いつものHTMLCSSJavaScript(Ajax)のみで、サーバー側も今まで通り普通にビューを返すだけです。

var content_id = '.content';$(function ($) {
    'use strict';
    if (window.history && window.history.pushState) {
        // click link with pushState
        $(document).on('click', 'a:not([href^="#"], [class*="ignore"])', function(e) {
            e.preventDefault();
            var url = $(this).attr('href');
            var title = $(this).attr('title');
            history.pushState({url: url, title: title}, title, url);
            getAction(url);
        });
        
        // form submit with pushState
        $(document).on('submit', 'form:not([action^="#"], [class*="ignore"])', function(e) {
            e.preventDefault();
            var url = $(this).attr('action');
            var title = $(this).attr('title');
            history.pushState({url: url, title: title}, title, url);
            postAction(url);
        });
        
        // send get 
        function getAction(url) {
            $.get(url, { push_state: 'true' }, function(data) {
                loadContent(data);
            })
            .fail(function() {
                loadError();
            });
        }
        
        // send post
        function postAction(url) {
            $.post(url, $("form").serialize(), function(data) {
                loadContent(data);
            })
            .fail(function() {
                loadError();
            });
        }
        
        // content
        function loadContent(data) {
            var title = $(data).find('title').html();
            var content = $(data).find(content_id).html();
            $('title').html(title);
            $(content_id).html(content);
        }
        
        // error
        function loadError() {
            location.href='/error' // or $(content_id).html('<h1>Error!</h1>');
        }
        
        // history back with popState
        $(window).on('popstate', function(e) {
            getAction(location.pathname);
        });
    }
});

Ajax + pushState の解説

初期設定

まずは、コンテンツを差し替えたい場所の要素を設定します。

var content_id = ".content";

次に、historyまたはpushStateが使えるブラウザかどうか判定します。
もし使えなければ、普通のWEBサイトとして表示します。

if (window.history && window.history.pushState) {
    ...
}

画面遷移のイベント

次に、リンクアンカー)をクリックした時の処理(GET)と、フォームをサブミットした時の処理(POST)を書きます。

// click link with pushState
$(document).on('click', 'a:not([href^="#"], [class*="ignore"])', function(e) {
    ...
}
// form submit with pushState
$(document).on('submit', 'form:not([action^="#"], [class*="ignore"])', function(e){
    ...
}

このイベントは、クリックまたはサブミットした際に遷移先のURLが「#」から始まらない、もしくはclassに「ignore」が存在しない場合に発生します。
イベントが発生したら、そのままページ遷移させないように、

e.preventDefault();

でイベントを一旦止め、

var url = $(this).attr('[属性名]');
var title = $(this).attr('title');
history.pushState({url: url, title: title}, title, url);

遷移先のURLやタイトルを取得し、ブラウザのURLを書き換えて履歴history.pushState)に登録。
最後に、GETの場合は、

getAction(url);

そして、POSTの場合は、

postAction(url);

関数を呼び出します。

GET/POST処理

関数内では、Ajax$.get()$.post()メソッドを呼び出しています。
応答が帰ってきたら、

loadContent(data);

を呼び出し、エラーの場合は、

errorContent(data);

を呼び出します。

コンテンツを読み込む

受っとったHTMLデータから、タイトルコンテンツを取り出して、

var title = $(data).find('title').html();
var content = $(data).find(content_id).html();

JavaScriptHTMLを差し替えます。

$('title').html(title);
$(content_id).html(content);

以上です。

ページを遷移する際にフェードインフェードアウトを使うともっとアプリらしく見えますね!
あと、アンカーに[target=”_blank”]があった場合も除外した方がいいかも。
まあ、参考サイトのように16行とはなりませんが、GETだけでなくPOSTにも対応した上、かなり軽量だと思います。

一応、GitHubに上げてますので、よかったらどうぞ。

モバイルバージョンを終了