完全な手順!VueJSで自動ページ送りする方法

さてさて、何かと最近はLaravelの話題ばかり記事を書いているので、この辺で一旦クライアントサイド、つまりJavaScriptに目を向けてみることにしました。

そして、このブログでJSと言えば、シンプル・コードで高機能を実現できる「Vue.js」です。

そこで!

今回は、スマホでもたまに見る「自動ページ送り」を実現する方法を順を追って説明してみることにしました。

ぜひVue開発の参考にしてみてくださいね。

やりたいこと

例えば、自社製品のリストが一行ずつ表示されている以下のようなページを思い浮かべてみてください。

そして、こういうコンテンツは件数が多くなってくると次へとか前へと書いたボタンやリンクでページ送りをしますよね。

もちろんこれでも問題はないのですが、例えば商品管理のページだったりすると毎回次へというリンクをカチカチとクリックし続ける必要があってめんどうだったりします。

そこで、今回やりたいことはページの一番下まで来たら自動的に次の商品データを表示する、自動ページ送りを実装する方法になります。

では、次から順を追ってどのように開発していくかを見ていきましょう。

※ HTMLコードに以下のようなvue.jsを読み込んでおいてください。(ちなみにこれはcdnです)

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.min.js"></script>

※ 実行環境はchrome 69 です。またJavaScriptコードは新しい書き方のES6で書いています。なのでIE11では動かないでしょう・・・もうIEはもう見捨てました ^^;

商品の一覧表示を実装する

まずは商品の一覧を表示する部分がなければ始まりませんので、この部分をVueを使って実装していきます。

まずHTMLにVueのターゲットになるidを追加します。

<div id="app">
</div>

そして、Vueの基本形を<script>〜</script>タグ内に書き込みます。#appは上のidになります。

new Vue({
    el: '#app'
});

次に必要な変数を追加。

new Vue({
    el: '#app',
    data: {
        products: [],
        pageNumber: 1,
        perPage: 25
    }
});

変数は以下のようになります。

  • products ・・・ 商品データが入る配列
  • pageNumber ・・・ 現在のページ番号(この数字が自動で増えるようにする)
  • perPage ・・・ ページごとに何件表示するか

では続いてmounted()を追加してページの準備ができたら即実行されるコードを追加します。

mounted() {

    this.products = [];

    for(let i = 1 ; i <= 1000 ; i++) {

        this.products.push('商品名 - '+ i);

    }

}

中身は、productsを初期化して以下のような商品名をテストデータとして1000個追加しています。

  • 商品名 – 1
  • 商品名 – 2
  • 商品名 – 3

ではこの商品リストを全て表示してみましょう。
配列をひとつずつ取り出すには、v-forを使います。

<div class="products" v-for="product in products" v-text="product"></div>

そして、ひとつずつ取り出したproductv-textを使って表示しています。

実行結果はこうなりました。

そうです。
このままだと一気に1000件表示されてしまって、ページ送りは実装できていません。

では次にpageNubmerが増えるごとに表示する件数を増やしていくコードつくっていきましょう。

中身が自動的に変更される擬似的な配列をつくる

VueJSには、あたかも変数かのように使うことができる「computed」という可変式の便利機能があります。

これを使って、pageNumberが変わるごとに商品リストのデータ件数が変わるコードを書いていきましょう。

名前はfilteredProductsとします。

computed: {
    filteredProducts() {

        const itemCount = this.pageNumber * this.perPage;
        let products = [];

        for(let product of this.products) {

            if(products.length === itemCount) {

                break;

            }

            products.push(product);

        }

        return products;

    }
}

中身は、itemCountが表示する商品リストの件数で、例えば以下のようになります。

  • pageNumberが「1」のとき ・・・ 全50件表示する
  • pageNumberが「2」のとき ・・・ 全100件表示する
  • pageNumberが「3」のとき ・・・ 全150件表示する

つまり、この数字は

pageNumber(現在のページ番号) × perPage(ページごとの件数)

の結果ということですね。

そして、for()ループの部分でproductsからデータをひとつずつとりながらproducts.lengthをチェックして、もし「全●件」の数字に達していたらbreak;でループを抜けるようにします。

こうすることで、pageNumberの数字が変更になったら自動的に商品リストの件数が変更になります。

では、この擬似的な配列を先ほどのv-forを使って表示してみましょう。

<div class="products" v-for="product in filteredProducts" v-text="product"></div>

この実行結果はこうなります。

では、テスト的にpageNumber2にしてリロードしてみましょう。

50件表示されました。
表示部分はこれでOKです。

スクロールイベントを実装する

では、次にスクロール・イベントを追加してページの一番下に来たらページ番号を増やすコードをつくりましょう。

mounted() {

    // 省略

    window.addEventListener('scroll', this.pager);
    this.pager();

}

イベントはページの準備ができた段階でaddEventListener()を使ってスクロール・イベントを追加します。実行する関数はpager()です。

※ ただし、表示直後に表示件数が少ないとスクロールバーが表示されずスクロール・イベントが一切実行されなくなる可能性があるので、pager()は起動後に直接実行するようにしています。

では、次にpager()関数です。
コードを書くのはmethods: {}内です。

methods: {
    pager() {

        if(window.scrollY + window.innerHeight === document.documentElement.clientHeight) {

            this.pageNumber++;

        }

    }
},

スクロールされるごとに関数内で実行しているのは、if()文を使って、もしスクロールが一番下まで来ていたらthis.pageNumber++;でページ番号を1増やす、つまり表示件数を自動的に増やすようにしています。

これで、自動ページ送り部分が完成です。

せっかくなので「読み込み中」も表示する

今回はテストなので直にデータを追加していますが、通常でしたらおそらくAjax通信などでデータを取得することになるでしょう。

そういう場合にはやはり、何も表示されないと訪問ユーザーは不安になってしまうので、「今データを読み込んでいますよ」、と表示してあげると親切でしょう。

では、これもVueを使って実装してみましょう。

data: {
    // 省略
    loading: false
},

まず、loadingという読み込み中かどうかを判断する変数を用意します。(loadingtrueなら読み込み中ということなります。)

そして、HTML内に以下のようにv-ifを使って、loadingtrueのときだけ表示するテキストを追加します。

<div v-if="loading">[読み込み中...]</div>

では、さっきのpager()の中にloadingが切り替わるコードを追加しましょう。

pager() {

    if(window.scrollY + window.innerHeight === document.documentElement.clientHeight) {

        this.loading = true;
        const timer = timer1 = setInterval(() => {

            this.pageNumber++;
            clearInterval(timer);
            this.loading = false;

        }, 1000);

    }

}

テストなので、setInterval()で[読み込み中]を1秒(=1000ミリ秒)間だけ表示するようにしています。

今回のコードをダウンロードする

今回の記事用に作ったコードを無料でダウンロードできます。VueJSはcdnで読み込んでいるので、zipファイルを展開してhtmlファイルをブラウザで表示するだけでサンプルを実行できますよ!

VueJSで自動ページ送りするサンプルコード

おわりに

今回はGoogle Chrome向けとしてES6でコードを書きましたが、やはりこっちの方がコード量が少なくなっていいですね。

しかも、アロー関数の中でもthisが普通に使えるのでVueJSとの相性もいいです。

まぁ、webpackとかgulpといったタスクランナーを使えばこの問題の解決は簡単なんでしょうけど、個人的な意見で言うと、ほんのちょっとしたテキストの変更だけでタスクランナーを起動しないといけない状況はどうなのかな??と思うフシがあったりします。(CSSを変更する場合はデザイナーさんにもタスクランナーの利用を強制することになるわけですしね・・・)

ということで、ぜひIEには引退してもらってedgeに完全以降する日を心待ちにしています。(IEしか動かないウェブアプリを使って業務をしている会社さんは絶対反対でしょうけどね・・・ ^^;)

ということで、今回はES6でVueを書いてみました。

ぜひ参考になれば幸いです!

ではでは〜。