LoginSignup
3
1

More than 3 years have passed since last update.

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

Posted at

前置き

pagination.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 ? 式2 : 式3
式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

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

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1