【Nuxt.js】pagination実践編:$router.pushで簡単実装！

# 前置き
![pagination.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469755/33cd22e3-eccb-b5b8-2494-fba3c701baaa.gif)
ページ数に応じて
urlと表示が変わるpaginationです🍒
**前回やった導入編と全く別物です！
こっちの方が簡単なので別パターンとして紹介🌟**

記事タイトルが紛らわしいので、
まとめて名称変えるかもしれません。
こちらの続きはまた別記事にて…！
https://note.com/aliz/n/n8bb439a426a8

firebaseを月曜日に公開予定でしたが、
Cloud Firestoreがバグり。。。
それが落ち着いてからにします☁️
今後は火・木に投稿していく予定です！

# 構成

・pagination部分をコンポーネント化
・使用するページからpropsでdataを渡す🎁
・ページ数をurlに表示させる🔍($router.push)
・全7ページで、ページ数に応じて表示を変更

# Step1: コンポーネントでpropsを用意

**【構成】**
使うコンテンツによって
最大ページ数などが変わるためpropsを使用
・query: ページネーションを使うコンテンツ
・length: ページの長さ
・now: 今いるページ


```Pagination.vue
<script>
export default {
 props: {
   query: {
     type: String,
     required: true,
   },
   length: {
     type: Number,
     required: true,
   },
   now: {
     type: Number,
     required: true,
   },
 },
}
</script>
```

# Step2: コンポーネントで戻る・進むボタンを追加

**【式】三項演算を使用**
式１ ? 式２ : 式３
式1がtrueなら式2、falseなら式3

```Pagination.vue
<template>
 <div>
   <button
     class="btn btn-prev"
     @click="$router.push(`?${query}=${now - 1 || 1}`)"
   >
     戻る
   </button>
   <button
     class="btn btn-next"
     @click="$router.push(`?${query}=${now + 1 <= length ? now + 1 : length}`)"
   >
     進む
   </button>
 </div>
</template>

<script>
export default {
 props: {
   query: {
     type: String,
     required: true,
   },
   length: {
     type: Number,
     required: true,
   },
   now: {
     type: Number,
     required: true,
   },
 },
}
</script>
```

**【解説】
◾️戻る**
・|| または

該当コンテンツページ内queryの
今いるページnowから1戻る、または1にする

**◾️進む**
該当コンテンツページ内の
今いるページに1を足して
・全体ページ数と同じ
・またはそれより小さい場合
今いるページから1進む
そうでなければ全体ページ数にする

つまり全体ページを7で、
現在いるページが7なら
7 + 1 <= 7 
falseになるので7のまま
それ以上進むことはないですね🍀


**あれ？😶**
【戻る】すごくシンプルに見えるのに…

```Pagination.vue
@click="$router.push(`?${query}=${now - 1 || 1}`)"
```

【進む】は何か長い。

```Pagination.vue
@click="$router.push(`?${query}=${now + 1 <= length ? now + 1 : length}`)"
```

これではダメなの？？？🌨

```Pagination.vue
@click="$router.push(`?${query}=${now + 1 || length}`)"
```

最大ページ数を越えてどんどん進みます笑
lengthの値はマイナスにはできません。
そのため制限をかけなくても
勝手に1で止まってくれるのですが…！
プラスは制限をかけないと止まりません🏃‍♀️💨

# Step3: コンポーネントでページ数を表示

**【構成】**
ページ数の表示部分を作りましょう！
・5ページまではページ数分のみ表示
・6ページ以上は…(三点リーダー)で中間を省略

**【CSS】**
毎度のことですが省きます。
・…はcssでdotクラスでborderを使用
・現在ページがをクラスバインディングで
　background-color, colorを変更🎨

**【if, if, if…】**
ifで沢山分岐しています笑
どこで並列になってるか分かりにくいですね🤔
コンパクトにして全体構造を把握しましょう。


**【Pagination.vue】**
主にインラインのコメントで解説！
コードでも並列部分を絵文字で区別しています。
🍀と🐥が並列で使われている部分です。
それ以外の絵文字は if の目印です！

```Pagination.vue
<template>
 <div
   // ページ数が1より大きい、2ページ以上の時のみページネーションを表示
   v-if="length > 1"
   class="list-item list-item-nav"
 >
   <button
     class="btn btn-prev"
     @click="$router.push(`?${query}=${now - 1 || 1}`)"
   >
     戻る
   </button>
   <ul class="list">
     // 1ページ目はどんな時でも固定表示のためif不要
     <li
       // クラスバインディング、{ class名: 式 }でtrueの時にクラスがつく
       :class="{ now: now === 1 }"
       class="item item-link"
       // 1ページを押すとurlが~/1になる
       @click="$router.push(`?${query}=1`)"
     >
       <span class="text">
         1
       </span>
     </li>
     // 🌟ここから分岐、最大ページ数が2より大きい3〜
     <template v-if="length > 2">
       // 🍀3以上5以下(=最大ページ数3,4,5の時)
            5ページまでの場合は、最大ページ数に応じて該当ページ数を表示
       <template v-if="length <= 5">
         <li
           :class="{ now: now === 2 }"
           class="item item-link"
           @click="$router.push(`?${query}=2`)"
         >
           <span class="text">
             2
           </span>
         </li>
         // 💭最大ページ数が3, 4, 5かつ3より大きい4, 5の時
         <template v-if="length > 3">
           <li
             :class="{ now: now === 3 }"
             class="item item-link"
             @click="$router.push(`?${query}=3`)"
           >
             <span class="text">
               3
             </span>
           </li>
           // 🍰最大ページ数が3, 4, 5かつ3より大きい4, 5かつ4より大きい5の時
           <template v-if="length > 4">
             <li
               :class="{ now: now === 4 }"
               class="item item-link"
               @click="$router.push(`?${query}=4`)"
             >
               <span class="text">
                 4
               </span>
             </li>
           </template>
         </template>
       </template>
       // 🍀でなければ(=最大ページが5より大きい6〜)
       <template v-else>
　　　　　 // 🐥最大ページ6〜かつ現在いるページが4より少ない(=1, 2, 3の時)
         <template v-if="now < 4">
           <li
             :class="{ now: now === 2 }"
             class="item item-link"
             @click="$router.push(`?${query}=2`)"
           >
             <span class="text">
               2
             </span>
           </li>
           <li
             :class="{ now: now === 3 }"
             class="item item-link"
             @click="$router.push(`?${query}=3`)"
           >
             <span class="text">
               3
             </span>
           </li>
           <li
             // 🍭現在いるページが4より少ないかつ、3ページ目にいる時
             v-if="now === 3"
             class="item item-link"
             @click="$router.push(`?${query}=4`)"
           >
             <span class="text">
               4
             </span>
           </li>
           <li class="item item-dots">
             <div class="dot" />
             <div class="dot" />
             <div class="dot" />
           </li>
         </template>
         // 🐥最大ページ6〜かつ現在いるページが1, 2, 3でなく4で〜
　　　　　　　　　現在いるページに2を出しても最大ページ数と同じか少なければ
　　　　　　　　　(4ページ目にいるなら4 + 2、最大ページ7の方が大きいためfalse)
              (6ページ目にいるなら6 + 2、最大ページ7より大きいためtrue)
         <template v-else-if="length <= now + 2">
           <li class="item item-dots">
             <div class="dot" />
             <div class="dot" />
             <div class="dot" />
           </li>
           // 🌷最大ページ数から2を引いた数字が現在いるページだったら
　　　　　　　　　最大ページ数から3を引いたページ数を表示させる
　　　　　　　　　(5ページ目にいるなら7-2 =5でtrue、7-3 =4が表示される)
           <li
             v-if="now === length - 2"
             class="item item-link"
             @click="$router.push(`?${query}=${length - 3}`)"
           >
             <span class="text">
               {{ length - 3 }}
             </span>
           </li>
           <li
             :class="{ now: now === length - 2 }"
             class="item item-link"
             @click="$router.push(`?${query}=${length - 2}`)"
           >
             <span class="text">
               {{ length - 2 }}
             </span>
           </li>
           <li
             :class="{ now: now === length - 1 }"
             class="item item-link"
             @click="$router.push(`?${query}=${length - 1}`)"
           >
             <span class="text">
               {{ length - 1 }}
             </span>
           </li>
         </template>
         // 🐥最大ページ6〜かつ、今までのパターンに該当しない
　　　　　　　　　(上の🐥のfalse、現在4ページの場合)
         <template v-else>
           <li class="item item-dots">
             <div class="dot" />
             <div class="dot" />
             <div class="dot" />
           </li>
           <li
             class="item item-link"
             @click="$router.push(`?${query}=${now - 1}`)"
           >
             <span class="text">
               {{ now - 1 }}
             </span>
           </li>
           <li class="item item-link now">
             <span class="text">
               {{ now }}
             </span>
           </li>
           <li
             class="item item-link"
             @click="$router.push(`?${query}=${now + 1}`)"
           >
             <span class="text">
               {{ now + 1 }}
             </span>
           </li>
           <li class="item item-dots">
             <div class="dot" />
             <div class="dot" />
             <div class="dot" />
           </li>
         </template>
       </template>
     </template>
     <li
       :class="{ now: now === length }"
       class="item item-link"
       @click="$router.push(`?${query}=${length}`)"
     >
       <span class="text">
         {{ length }}
       </span>
     </li>
   </ul>
   <button
     class="btn btn-next"
     @click="$router.push(`?${query}=${now + 1 <= length ? now + 1 : length}`)"
   >
     進む
   </button>
 </div>
</template>

<script>
export default {
 props: {
   query: {
     type: String,
     required: true,
   },
   length: {
     type: Number,
     required: true,
   },
   now: {
     type: Number,
     required: true,
   },
 },
}
</script>
```

これで完成です🤗

**【最大ページ2は？】**
if は最大ページ3以上で分岐。
2はどうなっているかというと…
ul 内の構造を黄色い枠で分けています🐥
・1固定表示
・3ページ以上で分岐
・最大ページ固定表示

2が最大の場合は
最大ページを表示させてるわけです🌟
![Frame 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469755/d7227349-6c92-791a-3aa2-27e06c0a003a.png)




# Step4: コンテンツページでpropsにdataを渡す

**【sample.vue】**

```Pagination.vue
<template>
<div class="page">
  <Pagination
     query="members"
     :length="7"
     :now="Number($route.query.members) || 1"
     class="nav"
   />
</div>
</template>

<script>
import Pagination from '~/components/Pagination.vue'

export default {
 components: {
   Pagination,
 },
 data() {
   return {
     members: [
       {
         name: aLiz
       },
     ],
   }
 },
}
</script>

<style lang="scss" scoped>
</style>
```


**このアカウントでは
Nuxt.js、Vue.jsを誰でも分かるよう、
超簡単に解説しています🎈😀
これからも発信していくので、
ぜひフォローしてください♪**
https://twitter.com/aLizlab