見出し画像

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

🎈 この記事はWPへ移行しました
【Nuxt.js】pagination実践編:$router.pushで簡単実装!

# 前置き

画像1

ページ数に応じて
urlと表示が変わるpaginationです🍒
前回やった導入編と全く別物です!
こっちの方が簡単なので別パターンとして紹介🌟

記事タイトルが紛らわしいので、
まとめて名称変えるかもしれません。
こちらの続きはまた別記事にて…!

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: コンポーネントで戻る・進むボタンを追加

スクリーンショット 2020-01-21 14.58.08

【式】三項演算を使用
式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のまま
それ以上進むことはないですね🍀


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

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

【進む】は何か長い。

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

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

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

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

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

スクリーンショット 2020-01-21 14.57.18

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

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

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

スクリーンショット 2020-01-21 15.37.10

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

<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 =5true7-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が最大の場合は
最大ページを表示させてるわけです🌟

画像5


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

【sample.vue】
queryはstring型のため
urlにページ数を入れたいなら
Numberに変更する必要があります。
Number($route.query.members) が
0 or falseなら1になる

・A || B
AまたはB の意味もありますが
A ? A : B 三項演算と同じでもあります!

<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>


次回はSEOの続きか、
TypeScriptの導入あたりをやります。
公開予定日は1/23(木)です。


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

🎈 この記事はWPへ移行しました
【Nuxt.js】pagination実践編:$router.pushで簡単実装!

この記事が気に入ったらサポートをしてみませんか?