Angularで無限スクロールをやったので一般のjqueryで。
dataTablesというプラグインです。
以前下記リンクで紹介していますが、ようわかっとらんかったんで(汗)再度書きます。
公式
ディフォルトだと無限スクロールではなく、ページ番号をつけてページャーリンクをクリックしたり、一画面に表示する件数をボタンで変えたりするプラグインのようですが、応用することで無限スクロールに対応させられます。
たとえば日本中の郵便番号を一覧表示するページがあり、これを無限スクロールで下記のように読み込むとします。
※一般的な無限スクロールと違い、見えている部分が常に一定になります。
このプラグインに限らずですが、ようは無限スクロールのポイントはどんなプラグインでも下記のようなところだと思います。
- スクロール量をJavaScript側で検知する
- 検知した場合プログラムにlimit,offsetの情報をつけてGETでアクセスする(一般的にはひたすら追加していくものが多いlimitはいらないことが多いかもです。)
- その情報をもとにフロント側にデータを返す
インストール
dataTablesとdataTableのプラグインであるdatatables.net-scrollerも同時に読み込みます。datatables.net-scrollerがないと、スクロールしてもアクセスがサーバー側に飛ばないので注意です。
bowerで下記のようにインストールできます。
1 2 3 4 5 6 |
bower install --save datatables.net bower install --save datatables.net-scroller #cssも同時にinstallしておきましょう。(cssはどのフレームワークを選ぶかによって若干変わってきます。詳しくはlinkを。) bower install --save datatables.net-dt bower install --save datatables.net-scroller-dt |
https://datatables.net/download/bower
ソース
HTML/JS側
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html"> <head> <title>一覧</title> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <link rel="stylesheet" href="./bower_components/datatables.net-dt/css/jquery.dataTables.min.css" > <link rel="stylesheet" href="./bower_components/datatables.net-scroller-dt/css/scroller.dataTables.min.css" > <script src="./bower_components/jquery/dist/jquery.min.js"></script> <script src="./bower_components/datatables.net/js/jquery.dataTables.min.js"></script> <script src="./bower_components/datatables.net-scroller/js/dataTables.scroller.min.js"></script> <script type="text/javascript" > $(document).ready(function() { $('#address').DataTable({ //このプロパティがないとサーバーと通信できません。 "bServerSide": true, //見えている領域の幅です。 "sScrollY": "300px", //これをつけないとページャーリンクや一覧表示項目数などもともとついてたリンクが見えてしまいます。 "sDom":"ti", //プログラム側のURLです。実際にはこのあとにGET句がいろいろとつきます。 "sAjaxSource": "http://192.168.1.28/library/public/address.php", //これをいれないとscrollが有効になりません。 "scroller": { loadingIndicator: true }, //件数表示はディフォルトでは英語なので日本語にしたい場合は下記のように記入します。 "language": { "emptyTable" : "データが登録されていません。", "info" : "_TOTAL_ 件中 _START_ 件から _END_ 件までを表示", "infoEmpty" : "", "loadingRecords" : "ロード中", "processing" : "処理中...", }}); }); </script> <body> <div>一覧</div> <table id="address" class="dataTable"> <thead> <tr> <th>id</th> <th>zip</th> <th>address1</th> <th>address2</th> <th>address3</th> </tr> </thead> </table> </body> </html> |
PHP側
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
<?php require_once dirname(__DIR__) .'/vendor/autoload.php'; require_once __DIR__ .'/config.php'; use Underbar\ArrayImpl as _; use Carbon\Carbon; use Monolog\Logger; use Monolog\Handler\StreamHandler; use Monolog\Formatter\LineFormatter; $logging_path = dirname(__DIR__) . '/logs/test_log.log'; $stream = new StreamHandler($logging_path, Logger::INFO); $logger = new Logger('foo_test'); $logger->pushHandler($stream); $logger->pushProcessor(function ($record) { $record['extra']['dummy'] = ''; return $record; }); /* * * DBの接続設定 */ try { //メインのDB ORM::configure( sprintf('%s:host=%s;dbname=%s;port=%d', DB_DSN, DB_HOST, DB_NAME, DB_PORT)); ORM::configure('username', DB_USER ); ORM::configure('password', DB_PASS ); ORM::configure('driver_options', array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8')); ORM::configure('logging', true); ORM::configure('logger', function($log_string) use ($logger) { $logger->addInfo('sql ' . $log_string ); }); } catch (Exception $e) { $app->halt(500, $e->getMessage()); } switch ($_SERVER ['REQUEST_METHOD']) { case 'GET' : $sEcho = ( isset($_GET['sEcho']) && preg_match( '/^\d+$/',$_GET['sEcho']) === 1 ) ? $_GET['sEcho']:1; $limit = ( isset($_GET['iDisplayLength']) && preg_match( '/^\d+$/',$_GET['iDisplayLength']) === 1 ) ? $_GET['iDisplayLength']:100; if($sEcho === "1") { $limit = 1000; } $offset = ( isset($_GET['iDisplayStart']) && preg_match( '/^\d+$/',$_GET['iDisplayStart']) === 1 ) ? $_GET['iDisplayStart']:0; $addressinfo = getAddress ($offset, $limit); $jsonData = formatDataTables($addressinfo); header('content-type: application/json; charset=utf-8'); echo json_encode ( $jsonData); exit(); break; } function getAddress ($offset, $limit) { $datas =[]; $query = ORM::for_table ( 'zip' ) ->select_many ( 'id', 'zip', 'address1', 'address2', 'address3'); $datas = $query->limit($limit) ->offset($offset) ->find_array (); return $datas; } function formatDataTables($addressinfo) { $data = _::map($addressinfo, function($address) { return array_values($address); }); //100000は大体の件数で、本当は全件数をとらないとだめ //iTotalRecordsとiTotalDisplayRecordsの違いはフィルタリングしたときなど return [ 'iTotalRecords' => "100000", 'aaData' => $data, "iTotalDisplayRecords"=>"100000", "aoColumns"=>["id","zip","address1","address2","address3"], "sEcho"=> $sEcho ]; } |
発行されるURLは下記のようなものです。
※プラグインがスクロールを検知すると自動的に下記のようなURLを生成します。
1 |
http://192.168.1.28/library/public/address.php?sEcho=1&iColumns=5&sColumns=%2C%2C%2C%2C&iDisplayStart=0&iDisplayLength=117&mDataProp_0=0&sSearch_0=&bRegex_0=false&bSearchable_0=true&bSortable_0=true&mDataProp_1=1&sSearch_1=&bRegex_1=false&bSearchable_1=true&bSortable_1=true&mDataProp_2=2&sSearch_2=&bRegex_2=false&bSearchable_2=true&bSortable_2=true&mDataProp_3=3&sSearch_3=&bRegex_3=false&bSearchable_3=true&bSortable_3=true&mDataProp_4=4&sSearch_4=&bRegex_4=false&bSearchable_4=true&bSortable_4=true&sSearch=&bRegex=false&iSortCol_0=0&sSortDir_0=asc&iSortingCols=1&_=1496832551767 |
今回重要な情報としてはlimitとoffsetですが、limitに相当するものがiDisplayLengthでoffsetがiDisplayStartです。また一番最初に画面にアクセスしたとき(スクロールをしていないとき)はiDisplayStart =0 , iDisplayLength =9でした。
これだと初回のページを読んだ時に空きができちゃうんですよね・・プロパティにいれて変えようとしましたが、反映されないので私の場合初回時(sEcho=1)のときに多めに読み込むようにしました。