Vuetifyのコンポーネントを利用すると見栄えのいいページネーションを簡単に設置することができます。Vuetifyのマニュアルには、v-paginationコンポーネントによるページネーションのタグは記述されていますが、どのようにvue.js上で設定を行い動作させるかについては説明はありません。

本文書では、最も簡単だと思われる方法でVuetifyのページネーションの設定方法を詳細に説明しています。Vuetifyのページネーションに興味がある人はぜひ参考にしてみてください。

vue.jsとVuetifyの環境について

本文書ではページネーションに焦点を当てているので、vue.jsとVuetifyの環境構築手順については説明を行なっていません。下記の文書の前半部分を参考に環境構築を行なってください。またVuefityの設定方法についても説明を行なっています。

ページネーションの設定

Vuefityのページネーション

Vuefityにはページネーション(v-pagination)のコンポーネントが準備されているので、コンポーネントを利用するためにVuetifyのドキュメントを確認します。

Vuetifyドキュメントページ
Vuetifyドキュメントページ

Usageの下に表示されるコードをApp.vueファイルにコピー&ペーストします。TEMPLATEとSCRIPTどちらも使います。


<template>
  <v-app>
    <v-app-bar app>
      <v-toolbar-title>
        <span>Vuetify Pagination</span>
      </v-toolbar-title>
    </v-app-bar>

    <v-content>
      <div class="text-center">
        <v-pagination
          v-model="page"
          :length="6"
        ></v-pagination>
      </div>     
    </v-content>
  </v-app>
</template>

<script>
export default {
  name: 'App',
  data () {
    return {
      page: 1,
    }
  },
}
</script>

ブラウザで確認するときれいなページネーションが上記のコードのみで表示されます。

ページネーションコンポーネント
ページネーションコンポーネント

v-paginationコンポーネントには、v-modelでpage、propsにlengthが設定されています。それぞれがどのような働きをするか確認しておきます。

lengthはページネーションの分割したページの数の設定を行います。lengthの値を変えるとページネーションに表示されているリンクの数が変わります。例えば6から10に変更すると下記のようになります。

lengthの設定変更
lengthの設定変更

v-modelのpageにはページ番号が保存されてます。dataプロパティでは、pageを1に設定しているので、ページネーションの1の部分だけ色が変わっていることがわかります。色が変わっていることでユーザは現在どのページを閲覧していているかを確認することができます。この値はdataプロパティのpageで変更することが可能なので4に変更すると下記のように4の部分の色が変わります。

pageの値を変更する
pageの値を変更する

表示されているページネーションの番号をクリックしてみてください。クリックするとクリックした番号の色が変わることが確認できます。

ページネーションが表示されることと数字のボタンをクリックするとそのボタンの色が変更されることはわかりましたが、この変化をvue.js側で検知するためにドキュメントのPROPSではなくEVENTSを確認します。

v-paginationコンポーネントのEvent
v-paginationコンポーネントのEvent

EVENTSの設定

v-paginationコンポーネントのEVETNSを見るとinputイベントがあります。どのようなことがinputイベントによって実現できるのか確認するために設定を行なってみましょう。マニュアルには、numberが取得できると記載があるのでinputイベントを設定し、メソッド名はgetNumberとします。


<v-pagination
  v-model="page"
  :length="6"
  @input = "getNumber"
></v-pagination>

scriptタグにメソッドの追加も行います。


export default {
  name: 'App',
  data () {
    return {
      page: 1,
    }
  },
  methods: {
    getNumber: function(number){
      console.log(number)
    },
  }
}

console.logでinputイベントが発生し、getNumberメソッドが実行されるとnumberを表示させる設定を行なったので、開発者ツールを開いた状態でページネーションの番号をクリックしてください。

番号をクリックするとクリックした数字を取得することができます。

v-paginationコンポーネントだけではページネーションが表示されるだけですが、ページネーションの番号をクリックするとクリックした番号が取得できることがわかりました。

クリックした番号に応じたページを表示させることができれば、ページネーションをvue.jsを使って制御することができます。そのためにはまず表示させるデータが必要なので、表示させるデータについて確認していきます。

表示するデータの作成

通常であればページに表示させるデータはaxiosなどを利用してデータを保持するサーバから取得を行います。しかし、今回は外部からデータを取得するのではなく手動でデータを作成します。

dataプロパティにlistsを追加して、ライフサイクルフックのmountedでデータの作成を行います。

mountedでデータの作成を行うので、ページにアクセスすると自動でデータの作成が行われます。

data () {
  return {
    page: 1,
    lists: [],
  }
},

データの作成は、まず99個の要素を持つ配列を作成して、map関数を使って配列のindexを含んだオブジェクトを登録しています。


mounted: function(){
  this.lists = new Array(99).fill().map((v,i)=> {
    return { id : i,title : 'Title' + i };
  });
}

データの作成ができたら、v-listタグとv-forタグを使って作成したデータをブラウザに表示させるコードを追加します。


<v-content>
  <div class="text-center">
    <v-list>
      <v-list-item v-for="list in lists" :key="list.index">
        <v-list-item-content>
          <v-list-item-title>{{ list.title }}</v-list-item-title>
        </v-list-item-content>
      </v-list-item>
    </v-list>

    <v-pagination
      v-model="page"
      :length="6"
      @input = "getNumber"
    ></v-pagination>
  </div>     
</v-content>

ブラウザで確認すると99件分のデータがリスト化されて表示されます。下記ではブラウザ上に一部のデータした表示していませんが、実際には99件分のデータが1つのページに表示されています。

作成したデータをリスト化して表示
作成したデータをリスト化して表示

上記のように1ページに大量のデータが表示されることはユーザビリティに優れているとは言えません。ページネーションを使って1ページに表示させるデータを制限していきます。

表示させるデータの数を設定

表示させるデータの数を設定するためには、作成したデータ配列から取り出す要素の数を指定することができれば実現可能です。そのためにここではslice関数を利用します。

例えば、下記のようにA, B, C…が入った配列にsliceを使って一番目の引数に2、2番目の引数に5を指定して実行すると配列番号2,3,4の3つの要素[‘C’,’D’,’E’]のみ取得することができます。


const alphabet = ['A','B','C','D','E','F','G'];

console.log(alphabet.slice(2,5))

>[ 'C', 'D', 'E' ]

slice関数の使用方法がわかったので作成したlistsの先頭から10個のデータをsliceを利用して取得するには下記のように記述します。


mounted: function(){
  this.lists = new Array(99).fill().map((v,i)=> {
    return { id : i,title : 'Title' + i };
  });
  this.lists = this.lists.slice(0,10);
}

ブラウザで確認すると下記のように表示されます。10件のみデータが表示されています。

slice関数を使って配列から一部を取リ出す
slice関数を使って配列から一部を取リ出す

1ページに表示させるサイズを設定するpageSizeと表示させるデータを保持するdisplayListsを新たにdataプロパティに追加します。


data () {
  return {
    page: 1,
    lists: [],
    displayLists: [],
    pageSize: 10,
  }
},

下記のように追加したdisplayListsをpageSizeを使って設定します。


mounted: function(){
  this.lists = new Array(99).fill().map((v,i)=> {
    return { id : i,title : 'Title' + i };
  });
  this.displayLists = this.lists.slice(0,this.pageSize);
}

これまではv-forでthis.listsを使っていましたが、this.displayListsに変更します。


<v-list-item v-for="list in displayLists" :key="list.index">
listsには全データを保持し、displayListsはブラウザに表示させるデータのみ保持させます。

this.displayListsを変更してもブラウザの表示は先ほどと変わりません。

slice関数を使って配列から一部を取リ出す
displayListsを使ってリスト表示

ここまでの設定では表示される内容がページネーションと連携していないので、ページネーションの番号をクリックしても色は変わりますが、それ以外のものは何も変化はありません。

ページネーションとの連携

inputイベントを利用して、ページネーションと表示させるデータを連携させます。

inputイベントで実行するメソッドの内容を更新します。更新と同時にメソッド名等を処理を表す名前に変更します。

ページの内容の変更に関連するメソッド名なのでgetNumberをpageChangeに変更し、functionの変数の名前をnumberからpageNumberに変更しています。

inputイベントで取得したpageNumberによってdisplayListsに保存する配列の要素を変えるためsliceの引数もpageSizeとpageNumberを使ったものに変更します。。


methods: {
  pageChange: function(pageNumber){
    this.displayLists = this.lists.slice(this.pageSize*(pageNumber -1), this.pageSize*(pageNumber));
  },
},

ページ番号が1であれば、slice(0,10)となり、ページ番号が2であれば、slice(10,20)になります。これでpageNumberに合わせて表示する内容を変更することができます。

ここまでの設定が完了したら、ページネーションの数字をクリックしてください。クリックするとページの内容が変わることが確認できればページネーションは連携しています。

ページネーションと表示される内容が連動
ページネーションと表示される内容が連動

99件のデータがありましたが、ページネーションには6番までの番号しか振られてないので、その先のデータを確認することができません。

ページネーションのページの数についてはlengthの設定で行えることは説明済みなのでlengthの設定について確認を行います。

lengthの設定

length設定はデータの件数と1ページあたりに表示する数に依存するため、それらの値を使って計算を行う必要があります。

配列の大きさはlengthメソッドを使い、1ページあたりのデータ数はpageSizeで設定を行なっているので、これらの2つの値を使ってlengthを算出します。


this.length = Math.ceil(this.lists.length/this.pageSize);
ceil関数は小数点以下の値を切り上げした結果もどもします。99の場合は10で割ると9.9ですが切り上げを行うので10になります。

lengthは6を設定していましたが、dataプロパティに新たにlengthを追加します。


data () {
  return {
    page: 1,
    length:0,
    lists: [],
    displayLists: [],
    pageSize: 10,
  }
},

v-paginationのpropsのlengthも6から追加したlengthに変更します。


<v-pagination
  v-model="page"
  :length="length"
  @input = "pageChange"
></v-pagination>

lengthはmountedでデータを作成したあと、作成したデータとpageSizeを利用して計算を行います。


mounted: function(){
  this.lists = new Array(99).fill().map((v,i)=> {
    return { id : i,title : 'Title' + i };
  });

  this.length = Math.ceil(this.lists.length/this.pageSize);

  this.displayLists = this.lists.slice(0,this.pageSize);
}

ブラウザで確認するとページネーションの数がデータの件数とpageSizeに応じた数に変わります。

ページネーションが6から10へ
ページネーションが6から10へ

pageSizeは10から50に変更すると1ページに表示させるデータは50件になり、ページネーションの数も2つになります。

pageSizeの値を変更した場合
pageSizeの値を変更した場合
ページネーションはpageSizeだけではなくデータの件数によっても変わります。データの件数が増えればページネーションの数も変わります。

アクセス時に表示するデータ

アクセス時に表示される内容はpageの値によって変更する必要があります。今の設定ではpageの値を3に変更しても1ページ目の内容が表示されます。

pageの値によって最初に表示されるデータが正しい内容に変わるようにmountedのdisplayListsを変更します。


mounted: function(){
  this.lists = new Array(99).fill().map((v,i)=> {
    return { id : i,title : 'Title' + i };
  });

  this.length = Math.ceil(this.lists.length/this.pageSize);

  this.displayLists = this.lists.slice(this.pageSize*(pageNumber -1), this.pageSize*(pageNumber));
}

これでpageを3に変更すると3ページ目の内容が表示されます。

作成したコード

Vuetifyのv-paginationを使うと見栄えのいいページネーションを簡単に設置できることが確認できました。

今回作成したApp.vueのコードは下記の通りです。


<template>
  <v-app>
    <v-app-bar app>
      <v-toolbar-title>
        <span>Vuetify Pagination</span>
      </v-toolbar-title>
    </v-app-bar>

    <v-content>
      <div class="text-center">
        <v-list>
          <v-list-item v-for="list in displayLists" :key="list.index">
            <v-list-item-content>
              <v-list-item-title>{{ list.title }}</v-list-item-title>
            </v-list-item-content>
          </v-list-item>
        </v-list>

        <v-pagination
          v-model="page"
          :length="length"
          @input = "pageChange"
        ></v-pagination>
      </div>     
    </v-content>
  </v-app>
</template>

<script>
export default {
  name: 'App',
  data () {
    return {
      page: 1,
      length:0,
      lists: [],
      displayLists: [],
      pageSize: 10,
    }
  },
  methods: {
    pageChange: function(pageNumber){
      this.displayLists = this.lists.slice(this.pageSize*(pageNumber -1), this.pageSize*(pageNumber));
    }
  },
  mounted: function(){
    this.lists = new Array(99).fill().map((v,i)=> {
      return { id : i,title : 'Title' + i };
    });

    this.length = Math.ceil(this.lists.length/this.pageSize);

    this.displayLists = this.lists.slice(this.pageSize*(this.page -1), this.pageSize*(this.page));
  }
}
</script>