When it’s ready.

出来るまで出来ない

超シンプルな、pushState + Ajax = PJAXのサンプル Flask編

HTML5熱いですね。いろんな意味で

BigPipeやら、HTMLでテンプレートエンジンとかいろいろ出ていますがユーザービリティ下げちゃいけないよねって事は、どの技術でも大切な共通項ですね。pjax = pushState + ajax使えば、リッチな人にはサクサクなUIを、そうじゃない人にもそれなりに提供できる。その上、戻るボタンもサーチエンジンにも優しいとくれば、これは試さないわけには行かないですね。

動作サンプル: http://pjax.atu.si/

Pjaxするとどうなるのか?

非同期動作時

http://pjax.atu.si にアクセスをして、リンクをクリックすると要素が非同期に変更される。
非同期に更新されているがURLは、シンプルなものに変更される。

同期動作時

http://pjax.atu.si/parts/xhttp://pjax.atu.si/parts/y にアクセスするとページ全体が、同期的に更新される。ローカルブラウザでレンダリングされない。


Pythonのサンプルが全然無かったので、Flaskで実装してみました。メチャシンプルですぉ
ファイル構成

.
├── __init__.py
├── main.py
├── static
│   └── js
│       ├── jquery-1.6.2.min.js
│       └── jquery.pjax.js
└── templates
    └── pjax.html

クライアント側

<!DOCTYPE HTML>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>PJAX and Flask</title>
  <script src="/static/js/jquery-1.6.2.min.js" type="text/javascript"></script>
  <script src="/static/js/jquery.pjax.js" type="text/javascript"></script>
  <script>
  //$(function() {
  $(document).ready(function() {
    console.log('load done');
    $('a').click(function(evt){
      evt.preventDefault();
      console.info(evt);
    });
    $("a.js-pjax").pjax("#main");
  });
  </script>
</head>
<body>
<a href="/parts/x" data-pjax="main" class='js-pjax'>パーツX</a><br>
<a href="/parts/y" data-pjax="main" class='js-pjax'>パーツY</a><br>
<div id="main">
{% if p.main  %}
 {{ p.main }}
{% endif %}
</div>
</body>
</html>
  • aタグのデフォルト動作をキャンセルし、パーツXとパーツYのリンクを乗っ取る。
  • $(リンク要素).pjax(DOM要素) で、リンク要素が押されるとX-PJAXヘッダー付きのリクエストが流れて、レスポンスがDOM要素に詰め込まれる。
#!/usr/bin/env python
#coding:utf-8


from flask import Flask,render_template, request
import os

os.chdir('/var/www/pjax_flask/src')
app = Flask(__file__)

@app.route('/')
def index():
  p = {}
  return render_template('pjax.html', p=p)

@app.route('/parts/<type>')
def get_parts(type):
  p = {}
  if "X-PJAX" in request.headers:
    return 'only parts %s'%(type)
  p['main'] = 'all page with parts %s'%(type)
  return render_template('pjax.html', p=p)

def main():
  app.run(host='0.0.0.0')

if __name__ == '__main__':
  app.debug = 1
  main()

パーツのリクエストが非同期で飛んで来る時は、jquery.pjaxがヘッダーにX-PJAX付与される。直接リクエストが来るときには、X-PJAXが付与されない。よって、非同期の時はパーツのみレスポンスし、直接リクエストが来る場合には、テンプレートを使ってレンダリングし全体をレスポンスとして返す。

やってみて

jquery.pjax理解するのが、大変だったけど実際に実装するのは簡単だった。
これくらいの手数が増える程度で、戻る対応出来たり、JS非対応ブラウザに対応出来たりするのは感動もの。
今後大きく利用される可能性があると感じるのは、動かしてみて挙動自体に違和感がなく想像通りに動いているっていうのところ。何でもかんでも新しいモノに変われば良いってもんじゃない、以前と同じように使えてるように見えて実はAJAX出来たり、それと同じ様に見えてるのに、非AJAXで動作してるっていうのがいいよね。

ソースはこちら : https://bitbucket.org/a2c/pjax_flask/