2019年10月22日火曜日

コピペでOK!Vue.jsでリアルタイム検索をつくる方法

https://blog.capilano-fw.com/?p=648
シェアしました。

コピペでOK!Vue.jsでリアルタイム検索をつくる方法

さてさて、この頃Laravel情報ばかりを記事にしているということで前回記事ではVue.jsの話題をお届けしました。ということで今回もその流れに乗ってVue.jsで知っておくととても便利なテクニックをご紹介したいと思います。
内容としては、「リアルタイム(オフライン)検索」です。
例えば以下のようなウェブページを想像してみてください。
  • ある施設をリスト表示する
  • リスト上部にある検索ボックスで検索ができる
  • その検索ボックスに入力した時点で該当するデータだけ表示する
つまり、検索はJavaScript側でするので毎回Ajax通信する必要がありません(オフラインで完結)。だから、とても高速に検索ができるというわけですね。
※ただし、ページが読み込まれる時点で全てのデータを用意する必要があるのであまりにもデータが多い場合はリアルタイム検索は向いてるとは言えません。その場合は通常通り1ページずつデータをAjaxで取得する方がいいでしょう。
では、Vue.jsを使って、この「リアルタイム検索」を実装してみましょう。

Vue.jsでリスト表示する

まずはVue.jsを使って5件のテストデータをリスト表示してみましょう。
<html>
<body>
<div id="app">
    <table>
        <tr v-for="user in users">
            <td v-text="user.id"></td>
            <td v-text="user.name"></td>
            <td v-text="user.email"></td>
        </tr>
    </table>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<script>

    new Vue({
        el: '#app',
        data: {
            users: [
                {
                    id: 1,
                    name: '鈴木太郎',
                    email: 'suzukitaro@example.com'
                },
                {
                    id: 2,
                    name: '佐藤二郎',
                    email: 'satoujiro@example.com'
                },
                {
                    id: 3,
                    name: '田中三郎',
                    email: 'tanakasaburo@example.com'
                },
                {
                    id: 4,
                    name: '山本四郎',
                    email: 'yamamotoshiro@example.com'
                },
                {
                    id: 5,
                    name: '高橋五郎',
                    email: 'takahashigoro@example.com'
                },
            ]
        }
    });

</script>
</body>
</html>
内容としては、データをVueのdataに格納して、それをv-forで一つずつ表示するだけのシンプルなものです。
実行結果はこうなります。

v-modelでバインディングした検索ボックスをつくる

次にリアルタイム検索をするための検索ボックスを追加します。
まず、dataに検索キーワード用の変数「keyword」を追加。
data: {
    keyword: '',
    users: [
        {
            id: 1,
            name: '鈴木太郎',
            email: 'suzukitaro@example.com'
        },
        {
            id: 2,
            name: '佐藤二郎',
            email: 'satoujiro@example.com'
        },
        {
            id: 3,
            name: '田中三郎',
            email: 'tanakasaburo@example.com'
        },
        {
            id: 4,
            name: '山本四郎',
            email: 'yamamotoshiro@example.com'
        },
        {
            id: 5,
            name: '高橋五郎',
            email: 'takahashigoro@example.com'
        },
    ]
}
そして、HTMLにv-modelが入ったinputタグを記述します。
<div id="app">
    <input type="text" v-model="keyword">
    <table>
        <tr v-for="user in users">
            <td v-text="user.id"></td>
            <td v-text="user.name"></td>
            <td v-text="user.email"></td>
        </tr>
    </table>
</div>
これを実行すると以下のようになります。

リアルタイム検索のロジックを追加する

では、ここからが本題のリアルタイム検索です。
検索ボックスに文字が入力された瞬間、関連データだけ表示する方法です。
まずリアルタイムにかかわらずデータ検索するには、データのフィルター機能が必要です。
例えば、検索ワードが「鈴木」でデータが以下のものだった場合、ひとつずつデータをチェックして「鈴木」という文字列が含まれているかどうかをチェックし、もし含まれているのならそのデータを残して他はスルーしなければいけません。
users: [
    {
        id: 1,
        name: '鈴木太郎',
        email: 'suzukitaro@example.com'
    },
    {
        id: 2,
        name: '佐藤二郎',
        email: 'satoujiro@example.com'
    },
    {
        id: 3,
        name: '田中三郎',
        email: 'tanakasaburo@example.com'
    },
    {
        id: 4,
        name: '山本四郎',
        email: 'yamamotoshiro@example.com'
    },
    {
        id: 5,
        name: '高橋五郎',
        email: 'takahashigoro@example.com'
    },
]
これを実装するためには、Vueのcomputedを利用するといいでしょう。
computedはデータが変更(つまり、ここでは検索キーワードが入力)されると同時にコンテンツ内容も変更することができますし、さらにキャッシュが効くので次回からのレンダリングも高速表示できるようになります。
※詳しくは、Vueの「methods」と「computed」の違いをご覧ください。
例えばこんな形です。
computed: {
    filteredUsers: function() {

        // ここにデータをフィルターするロジック

    }
}
そして、computedで作成したキー(ここではfilteredUsers)は以下のように変数の代わりとして利用することができます。
<table>
    <tr v-for="user in filteredUsers">
        <td v-text="user.id"></td>
        <td v-text="user.name"></td>
        <td v-text="user.email"></td>
    </tr>
</table>
これで、あとはデータをフィルターするロジックを記述してやれば、リアルタイム検索は完成です。
実際のコードはこうなります。
filteredUsers: function() {

    var users = [];

    for(var i in this.users) {

        var user = this.users[i];

        if(user.name.indexOf(this.keyword) !== -1) {

            users.push(user);

        }

    }

    return users;

}
例のIEも考慮にいれているのでES6ではなくてすみません。(IEさん、もうね・・・・^^;)
重要なのはif文で各データに検索キーワードが含まれているかチェックしている部分です。もし含まれていれば、配列usersにそのデータを追加するようになっています。
さらに、もしnameだけじゃなくemailでもフィルターをかけたい場合は以下のようにするといいでしょう。
if(user.name.indexOf(this.keyword) !== -1 ||
    user.email.indexOf(this.keyword) !== -1) {

    users.push(user);

}
はい!
これだけでVueのリアルタイム検索は完成です。昔と比べると格段に効率が上がってますね。

実際の全コード

以下が今回テスト用に作ったリアルタイム検索の全コードです。
Vue.jsもcdnを読み込んでいるので、このままコピペで動くと思います。
<html>
<body>
<div id="app">
    <input type="text" v-model="keyword">
    <table>
        <tr v-for="user in filteredUsers">
            <td v-text="user.id"></td>
            <td v-text="user.name"></td>
            <td v-text="user.email"></td>
        </tr>
    </table>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.min.js"></script>
<script>

    new Vue({
        el: '#app',
        data: {
            keyword: '',
            users: [
                {
                    id: 1,
                    name: '鈴木太郎',
                    email: 'suzukitaro@example.com'
                },
                {
                    id: 2,
                    name: '佐藤二郎',
                    email: 'satoujiro@example.com'
                },
                {
                    id: 3,
                    name: '田中三郎',
                    email: 'tanakasaburo@example.com'
                },
                {
                    id: 4,
                    name: '山本四郎',
                    email: 'yamamotoshiro@example.com'
                },
                {
                    id: 5,
                    name: '高橋五郎',
                    email: 'takahashigoro@example.com'
                },
            ]
        },
        computed: {
            filteredUsers: function() {

                var users = [];

                for(var i in this.users) {

                    var user = this.users[i];

                    if(user.name.indexOf(this.keyword) !== -1 ||
                        user.email.indexOf(this.keyword) !== -1) {

                        users.push(user);

                    }

                }

                return users;

            }
        }
    });

</script>
</body>
</html>

実行結果(サンプル)

今回の実行結果はこちらです。

おわりに

ということで今回はVue.jsを使ってリアルタイム検索を作る方法をお届けしました。
ここまで短いコードでこういうページを作れるってやっぱりバインディングは強力ですね!
ぜひみなさんも開発に役立ててくださいね。
ではでは〜!

0 コメント:

コメントを投稿