Vueにおいてのデータ結果のページング

## 1.概要
現在、VueとJavaで課題を作成中です。
Vueにおいて、データ検索のダイアログ画面を実装中で、その際に出てきたよく見る、データの検索結果をページングで表示する実装を掲載します。
検索結果が少なく、簡素な作りのため、個人開発や小規模な範囲でのものの使用に限ったほうが良いと思われます。
   
## 2.　実装結果のデザイン
上記は検索結果の全件を１０件単位でページングした場合のレイアウトです。
最初で、ページングの先頭へ、
最後で、ページングの最後へ、
番号を押すことで10の倍数の範囲で移動します。

![7023DCCE-8F98-4358-85E6-BB377277C07D.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583781/621794b3-e961-3ee3-2d10-0e281dc00a1e.jpeg)


## 3.　実装した内容

① 【検索ダイアログのコンポーネント】（土台は別にあり）
```vuejs:TalentRefSearchJoken.vue
<template>
  <div>
    <table align="center">
        // 途中は割愛
    </table>
    <br>
    <div>
      <button v-on:click="btnSearch()" class="rounded-ref-button">
        検索
      </button>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      <button v-on:click="btnClear()" class="rounded-ref-button">
        クリア
      </button>
    </div>
    <br>
    <div style="overflow-y: auto;">
      <table align="center" border="1" style="border-collapse: collapse;" class="result-table" v-if="isCount">
        <tr>
          <td style="background-color: greenyellow;"></td>
          <td style="background-color: greenyellow;">タレントID </td>
          <td style="background-color: greenyellow;">タレント名 </td>
          <td style="background-color: greenyellow;" v-if="isTalentToroku">ジャンルID</td>
        </tr>
        <tr v-for="(item, key) in paginatedResult" :key="key">
          <td><button v-on:click="selectTalent(item.talentId, item.talentName, item.genreId)" class="rounded-ref-button">選択</button></td>
          <td v-if="isTalentToroku">
              {{ item.talentId }}
          </td>
          <td v-else>
            <router-link :to="{ name: 'TalentTorokuKoshin', params: { talentId: item.talentId } }">{{ item.talentId }}</router-link>
          </td>
          <td>{{ item.talentName }} </td>
          <td v-if="isTalentToroku">{{ item.genreId }} </td>
        </tr>
      </table>
      <div v-if="isCount">
        <DataGridViewPaging
          :currentPage="currentPage"
          :totalPages="totalPages"
          :totalPageLinks="totalPageLinks"
          :changePage="changePage"
        />
      </div>
    </div>
    <br>
  </div>
</template>

<script>
// 割愛
import DataGridViewPaging from '../../common/DataGridViewPaging.vue';

export default 
  name: 'TalentRefSearchJoken',
  props: {
    // 割愛
  },
  components: {
    DataGridViewPaging,
  },
  data() {
    return {
      talentId: '',
      talentName: '',
      msg: '',
      url: '',
      isCount: false,
      result: {},
      currentPage: 1,
      pageSize: 10,
      totalPages: 0,
      maxPageLinks: 10,
    }
  },
  async created() {
    // 割愛
  },
  computed: {
    paginatedResult() {
      // ページングされた結果を返すように変更
      const startIndex = (this.currentPage - 1) * this.pageSize;
      const endIndex = startIndex + this.pageSize;
      return this.result.slice(startIndex, endIndex);
    },
    totalPageLinks() {
      const currentGroup = Math.ceil(this.currentPage / this.maxPageLinks);
      const startPage = (currentGroup - 1) * this.maxPageLinks + 1;
      const endPage = Math.min(currentGroup * this.maxPageLinks, this.totalPages);
      return Array.from({ length: endPage - startPage + 1 }, (_, index) => startPage + index);
    },
  },
  methods: {
    btnSearch() {
      this.fetchData();
    },
    async fetchData() {
     //API取得
     this.url= APIのURL
      this.result = await axios.get(this.url).then(response => (response.data));
      if (this.result.length !== 0) {
        this.isCount = true;
        // 途中は割愛
        this.resultCount = this.result.length; // 件数を更新
        this.totalPages = Math.ceil(this.result.length / this.pageSize);
      } else {
        // 途中は割愛
        this.isCount = false
      }
    },
    changePage(pageNumber) {
      this.currentPage = pageNumber;
      this.fetchData(); // ページ変更時にデータを再取得するなどの処理を追加
    },
    selectTalent(talentId, talentName, genreId) {
       // 途中は割愛
    },
    btnClear() {
        // 途中は割愛
    },
    init(){
        // 途中は割愛
    },
  },
}
</script>
<style scoped>
</style>
```

② 【ページングの部品のコンポーネント】
```vuejs:DataGridViewPaging.vue
<template>
    <div v-if="totalPages > 1" class="pagination-container">
        <div v-if="totalPages > 1" class="pagination-container">
        <a @click="changePage(1)" :disabled="currentPage === 1" class="pagination-link">最初</a>
        <a v-for="pageNumber in totalPageLinks" :key="pageNumber"
            @click="pageNumber !== '...' ? changePage(pageNumber) : null" class="pagination-link">
            <span v-if="pageNumber !== '...'">
                <span class="underlined">{{ pageNumber }}</span>
            </span>
            <span v-else>...</span>
        </a>
        <a @click="changePage(totalPages)" :disabled="currentPage === totalPages" class="pagination-link">最後</a>
        </div>
    </div>
</template>

<script>
export default {
    props: {
        currentPage: {
            type: Number,
            required: true,
        },
        totalPages: {
            type: Number,
            required: true,
        },
        totalPageLinks: {
            type: Array,
            required: true,
        },
        changePage: {
            type: Function,
            required: true,
        },
    },
};
</script>

<style scoped>
</style>
```

## ４. まとめ
よく使うページングですが、個人で実装したのは初めてでした。
理想的にはプルダウンで何件まで一度に表示するかなども追加したかったですが、
簡素な最低限だけ今回は実装しました。
またVueの部品作成についてはアップしてきます。