質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.80%

リストを分割してページ送りで表示を切り替える

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 7,022

score 609

リストを分割して表示するために、現在jQueryを利用して次の様にしています。
これをjQueryではなく素のJavaScriptで実装しようとしているのですが、ページ送りを表示させる箇所などで躓いており行き詰まっています。
ページ送りを含めたこの先の実装もですが、全体的に見てもっとスマートなコードに書き直せる等もあればアドバイスを頂ける嬉しいです。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>

<div id="parent">
  <div>
    <ul>
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
      <li>item4</li>
    </ul>
  </div>

  <div>
    <ul>
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
      <li>item4</li>
      <li>item5</li>
      <li>item6</li>
    </ul>
  </div>

  <div>
    <ul>
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
      <li>item4</li>
      <li>item5</li>
      <li>item6</li>
      <li>item7</li>
      <li>item8</li>
    </ul>
  </div>
</div>

</body>
</html>
// jQuery
;( function ( $ ) {

    $.fn.listsplit = function ( perPage ) {

        return this.each( function () {

            // 分割するリストの親要素
            var $base = $( this );

            // 分割するリスト
            var $list = $base.find( 'ul' );

            // 分割するリストアイテム
            var $item = $list.find( 'li' );

            // 分割するリストの長さ
            var length = $item.length;

            // 分割を開始する数
            if( perPage ) {
                var split = perPage; // 指定値
            } else {
                var split = 10; // 初期値
            }

            // リストアイテムが指定値より多い時に処理を開始
            if( length > split ) {

                // カウントを変数にセット
                var i = 0;

                // 指定値のグループに分割してクラスを追加
                while( i < length ) {
                    var group = i * split;
                    var division = group + split;
                    for( var z = group; z < division; z++ ) {
                        $item.eq( z ).addClass( 'p-' + ( i + 1 ) );
                    }
                    i++;
                }

                // ページ送り
                var last = Math.ceil( length / split );
                var current = 1;
                var pagenation = '<div class="list-pagenation">\n<span class="list-prev">prev</span>\n<span class="list-next">next</span>\n<span class="counter"><span class="current">' + current + '</span>/<span class="last">' + last + '</span></span>\n</div>\n';
                $list.before( pagenation );
                var $prev = $base.find( '.list-prev' );
                var $next = $base.find( '.list-next' );
                var $current = $base.find( '.current' );
                var $last = $base.find( '.last' );
                var $total = $base.find( '.total' );
                $current.html( current );
                $last.html( last );
                $total.html( length );
                $prev.addClass( 'disabled' );

                // リスト表示の初期設定
                $item.hide();
                $base.find( '.p-1' ).show();

                // 次へ
                $next.on( 'click', function () {

                    var page = $current.html();
                    var setnums = Number( page ) + 1;

                    if( setnums <= last ) {
                    $prev.removeClass( 'disabled' );
                        $current.html( setnums );
                        $item.hide();
                        $base.find( '.p-' + setnums ).stop( true, true ).fadeIn( 'fast' );
                    }

                    if( setnums == last ) {
                        $next.addClass( 'disabled' );
                    }

                });

                // 前へ
                $prev.click( function () {

                    var page = $current.html();
                    var setnums = Number( page ) - 1;

                    if( 1 <= setnums ) {
                        $next.removeClass( 'disabled' );
                        $current.html( setnums );
                        $item.hide();
                        $base.find( '.p-' + setnums ).stop( true, true ).fadeIn( 'fast' );
                    }

                    if( setnums == 1 ) {
                        $prev.addClass( 'disabled' );
                    }

                });

            }

        });

    };

})( jQuery );

$( function() {

    $( '#parent' ).find( 'div' ).listsplit( 2 );

});

JavaScriptによる実装の途中(随時更新)
表示・非表示はjQueryとは違って.hidden { display: none }というクラスを使って行う予定
// Pure JavaScript
function eq( index ) {
    if( index >= 0 && index < this.length ) {
        return this[index];
    } else {
        return -1;
    }
}

function list_split( element ) {
    'use strict';
    // リストを取得
    var list = element.getElementsByTagName( 'ul' );
    // リストアイテムを取得
    var item = list[0].getElementsByTagName( 'li' );
    // リストアイテムの数を取得
    var length = item.length;
    // 分割を開始するリストアイテムの数
    var split = 2;
    // カウント
    var i = 0;
    // 指定したポジションの要素を代入するための変数
    var index;

    // 指定値のグループに分割してクラスを追加
    while( i < length ) {
        var group = i * split;
        var division = group + split;
        for( var z = group; z < division; z++ ) {
            index = eq.call( item, z );
            if ( typeof index === 'object' ) {
                index.classList.add( 'p-' + ( i + 1 ) );
            }
        }
        i++;
    }

    // 最後のページ
    var last = Math.ceil( length / split );
    // 現在のページ
    var current = 1;

    // ページ送り用のノードを作成
    var pagenations = document.createDocumentFragment();

    // ページ送りをノードに追加
    var pagenation = document.createElement( 'div' );
    pagenation.className = 'list-pagenation';
    pagenations.appendChild( pagenation );

    // 前へ戻るボタンをページ送りに追加
    var page_prev = document.createElement( 'span' );
    page_prev.className = 'list-prev';
    page_prev.appendChild( document.createTextNode( 'Prev' ) );
    pagenation.appendChild( page_prev );

    // 次へ進むボタンをページ送りに追加
    var page_next = document.createElement( 'span' );
    page_next.className = 'list-next';
    page_next.appendChild( document.createTextNode( 'Next' ) );
    pagenation.appendChild( page_next );

    // カウンターをノードに追加
    var page_counter = document.createElement( 'span' );
    page_counter.className = 'counter';
    pagenations.appendChild( page_counter );

    // 現在のページをカウンターに追加
    var page_current = document.createElement( 'span' );
    page_current.className = 'current';
    page_current.appendChild( document.createTextNode( current ) );
    page_counter.appendChild( page_current );

    // ページ表示の区切りをカウンターに追加
    var partition = document.createTextNode( '/' );
    page_counter.appendChild( partition );

    // 最後のページをカウンターに追加
    var page_last = document.createElement( 'span' );
    page_last.className = 'last';
    page_last.appendChild( document.createTextNode( last ) );
    page_counter.appendChild( page_last );

    var list_parent = list[0].parentNode;
    list_parent.insertBefore( pagenations, list[0] );

    // 課題1: ページ送りを各リストの直前に挿入する
    // 課題2: 変数 last の値を各リストと連動した形で反映させる
}

document.addEventListener( 'DOMContentLoaded', function () {

    var parent = document.getElementById( 'parent' );
    var target = parent.getElementsByTagName( 'div' );
    var length = target.length;

    for ( var i = 0; i < length; i++ ) {
        list_split( target[i] );
    }

});
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

teratail questions-16480 への回答 - JSFiddle にサンプルコードをUPしました。

 - おそらく、見慣れないと思われるのは WAI-ARIA の aria-hidden属性でしょうか。
 - element.classList の classList.contains を使用すると更にスマートに書けますが、対象ブラウザが不明だったので一応、IE9 を基準としました。Polyfill を書くなら classList の方がベターだと思います。

(2015/09/20 10:25追記)
classList.contains を使用したコードをUPしました。IE9 用に className による代替コードも加えている為、IE9+ で動作します。
teratail questions-16480 への回答 - JSFiddle

(2015/09/20 10:31追記)
className による代替コードが不完全だったのを修正しました。
teratail questions-16480 への回答 - JSFiddle

(3015/09/21 07:38追記)
pagesize で element.children.length を割り切れなかった場合に TypeError で強制終了する不具合を修正しました。
teratail questions-16480 への回答 - JSFiddle

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/21 01:22

    item9まであるリストのdata-pagesizeの値を2にすると、カウントとページ送りの動作がおかしくなってしまうのですが、どう修正したら良いのか分かりません…。

    キャンセル

  • 2015/09/21 07:41

    確かに pagesize で割り切れない場合を考慮していなかったですね。コンソールを見ればどこでエラーが発生しているのがわかり、問題を特定しやすいと思います。
    修正して親コメントに追記しました。

    キャンセル

  • 2015/09/21 09:52

    修正して下さりありがとうございます。
    Math.minを使うだけで解決するのですね。
    コンソールでエラーは見ていたのですが、私にはまだ基礎知識が足りないみたいです…。
    もっとリファレンスを覚えて基礎をしっかりと身につけていこうと思います。

    キャンセル

0

list.js というライブラリーをつかってみてはどうでしょう?

http://www.listjs.com/examples/pagination

私はつかったことがありませんが、他のライブラリーも紹介します。

その他:
- jQueryでページ分割ができる「SimplePaginationプラグイン」 http://www.koikikukan.com/archives/2014/12/17-013333.php
- テーブルの表組みにページネーションをつけるJavaScript「Table Pagination」 http://www.skuare.net/test/jtablePagination.html
- テーブルに検索、ソート、ページネーション機能をもたせるDATATABLESプラグインhttp://endoyuta.com/2014/11/13/datatables/

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/21 09:36 編集

    回答して下さりありがとうございます。
    今回はjQueryで実装していたものを素のJavaScriptに置き換えてコンパクトにしたいという狙いがあり、ページ送りもPrevとNextだけのシンプルなものにしたいので、紹介して下さったライブラリは残念ながら利用出来ません…。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.80%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る