見出し画像

Vue.jsとjQueryで同じ機能を作成し、コードを比較する - その2

この記事は、Qiitaに投稿した「Vue.jsとjQueryで同じ機能を作成し、コードを比較する」の続編になります。

はじめに

エンジニアという世界にもムラがある。一部の炎上商法エンジニアたちのムラから脱出した私がたどり着いたのは、Vue.jsという新世界ブルーオーシャンだった!

……前置きはここまでにします。すません。ポエマーなんです✎

この記事の到着点

今回は、Vue.jsとjQueryのコードを比較し、両者の特性をあぶり出します。例えばJSONのような形式のデータをview側に展開したときに、どのように処理をするのかという点に絞って書いていきます。

コードの比較

前回、Vue.jsとjQueryで、その設計思想の違いの一端を書きました。最大の違いは以下の点です。

jQuery:既存のDOMを操作する
Vue.js:仮想DOMを構築し、指定したIDにDOMを描画する

以下に前回作成のサンプルを掲載します。両者で全く同じ機能を実現していますが、コードの書き方が違うことがわかるかと思います。

今回は上記のサンプルに「JSON形式のデータを入れる」という条件を更かします。早速ですが、こちらもサンプルを掲載します。

ハルキストではないですよ!(カフカくんのように屈強な若者になりたかったよ)

早速コードを見てみましょう!まず、下記のデータが用意されてます。

const list = [
  {
    uid: 1,
    title: '風の歌を聴け',
    detail: '1979年7月23日発行'
  },
  {
    uid: 2,
    title: '羊をめぐる冒険',
    detail: '1982年10月13日発行'
  },
  {
    uid: 3,
    title: '海辺のカフカ',
    detail: '2002年9月12日発行'
  }
];

こいつをそれなりの形で画面に描画します。まず、jQuery。

// ____ jQuery ____

list.forEach(function (item) {
    const $item = $('<div>').append('<h2>' + item.title + '</h2>')
        .append('<button class="js-btn">説明をみる</button>')
        .append('<p class="detail hide">' + item.detail + '</p>');
    $('#jquery').append($item);
});

$('#jquery .js-btn').on('click', function () {
    $(this).parent().find('.detail').toggle().toggleClass('hide');

    if ($(this).parent().find('.detail').hasClass('hide')) {
        $(this).text('説明をみる');
    } else {
        $(this).text('説明を閉じる');
    }
});

jQueryでの処理手順は下記の通り

1、JSON形式のlistをforEachで回す
2、listからitemという名で取り出したものを$itemにappendしていく。ついでにボタン「説明をみる」も作成し挿入する
3、html側の#jqueryに対して$itemを挿入する
4、「説明をみる」ボタンにclickイベントを付与する(説明文はCSSで最初から隠している)

もっと簡単にできそうな気もしますが、一旦こんな感じです😓
jQueryでJSON形式のデータを描画するには、forEachで一件ずつデータを取り出し、jQueryでDOMを作成し、結合していく作業が必要になるかと思います。今回のサンプルではまだ単純ですが、これが

・セレクトボックスによって描画内容を変更する
・提供されるJSONが複数ある

などの条件が加わると、かなりヤバイです(とある受託案件で身を持って経験済み;)

では、次にVue.jsではどうなるか見てみましょう!

// ____ Vue.js ____

Vue.component('item-detail', {
    data() {
        return {
            hide: true
        }
    },
    props: ['item'],
    methods: {
        toggleText() {
            if (this.hide) {
                return '説明をみる'
            } else {
                return '説明を閉じる'
            }
        }
    },

    template: `
        <div>
            <button v-on:click="hide = !hide">{{ toggleText() }}</button>
            <p :class="{ hide }">{{ item.detail }}</p>
        </div>
  `
});

Vue.component('hello-vue', {
    data() {
        return {
            list: list,
        }
    },
    template: `
        <div>
            <div v-for="item in list" :key="item.uid">
                <h2>{{ item.title }}</h2>
                <item-detail :item="item" />
            </div>
        </div>
    `
});

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

ちょっと長いですが、Vue.jsの処理手順は下記の通りです。処理の手順として、コードの下から上に向かって説明します。

new Vue()

1、「el」は、テンプレートの描画先(レンダリング)を指定します。通常はIDを記載します。

Vue.component('hello-vue', { ... });

1、Vue.componentとは、Vue.jsにコンポーネントを登録しますよ、というものです。第一引数にコンポーネント名を、第二引数に具体的な内容を記載していきます。

2、今回は、コンポーネント「hello-vue」を作成する。その中にdataオブジェクト「list」を作成し、最初にJSONデータを読み込む(読み込み処理は端折ってます)

3、templateにそのまま展開されるhtmlを記載する。その中でオブジェクトの数だけループするtemplate構文「v-for」を使い、listオブジェクトの中身をitemとして展開する。Vue.jsではv-forを使うときにユニークなキーを一件ずつ割り当てる必要があります(今回はJSON内に記載されているuidを使用した)

4、展開されたitemの中に「title」「detail」データがあり、titleをmustache記法({{ xxx }}で囲う)でtitleの中身をテキストとして展開する

5、子コンポーネント「item-detail」(詳細は後述)にitemをまるごと渡します。Vue.jsでは、template内でコンポーネントを使用する際に「<xxx-xxx />」と書き、使用することができます。また、「:xxx=...」とは、変数を子コンポーネントに渡す記載方法です。「:渡す変数名="値"」と書きます。

Vue.component('item-detail', { ... });

1、前項で説明した箇所はいくつか端折ります(p_-)
コンポーネント「item-detail」は、前項の「5」で渡したitemを受け取るために、「props」変数を定義します。propsは、親のコンポーネントから何らかのデータを受け取るために用意されています(単方向データバインディングという)propsは、親コンポーネントで「:変数名」で指定した変数名と同じ名前を入れます。

2、template内にある「v-on:click」とは、記載されているDOMオブジェクトをクリックした際に特定の処理を実行する、というものです。今回はdataオブジェクト内のbool型の「hide」をクリックのたびに反転させています。data内の値が変わると、対応するDOMの状態も変わります(これをリアクティブシステムといいます)。今回はhideは本文の表示非表示に使用しています。「:class="{ hide }"」は、CSSのクラスを変数の結果で書き出す(動的に)ためのものです。ここでは「hide」クラスがボタンをクリックするたびに付与されたり削除されるので、表示非表示を切り替えるようにしています。

3、methodsとは、名の通り各関数をまとめる場所です。たとえば、toggleText()を別の書き方で書くとfunction toggleText() { ... }となります。今回は「this.hide」がtrueだと「説明を見る」が、falseだと「説明を閉じる」が帰ってくる関数です。ボタンのテキスト「{{ toggleText() }}」で使用しています。mustache記法で、値を返す関数を指定すると、返ってきた値がそのまま入ります。ところで、this.hideはhideを指定しています。thisは、自身のコンポーネントのdata、また、methodsの関数名を指す際に使用します。(template構文内の変数はthisを記載する必要はないです)

考察

以上がVue.jsでの記載方法です。長くなりましたが、各機能が明確に分割されているかと思います。
例えば、上記のコンポーネント「item-detail」を他の人に任せて作業させても良いかもしれません。親コンポーネントから渡すデータ仕様を作業者に伝えれば、担当者が自分のPCに持ち帰って作業することが可能です。
jQueryで処理した場合は、イベント単位でのコーディングになりがちで、html, css, jsそれぞれに手を入れていかなければならなくなります。そうすると、全てのファイルを編集して、Gitでマージするときにコンフリクトして…などとすることになります;;

さいごに

自分はQiitaからnoteに移動した勢です。理由として、Qiita上において「つっこめる記事を探し出してそれを眺めて楽しもう」とか「クソ記事垂れ流すな」というような風潮が強くなってきたのを感じたからです。

私は、一エンジニアとして誰かのためになる記事を書きたい、ついでに記事を書くために調べ物をして勉強にもなるじゃん!という姿勢で記事を書こうという姿勢です。ところが、上記のような風潮が強まると

「人につっこまれないように予防線を貼ろう」
「これ、記事にしたら良いかな?でも、よく考えたら大した内容じゃないから、やめよう」

とか、後ろ向きな考えで記事作成に挑まなければならなくなる。そういう状況に耐えられなくなってきたのが主な理由です。なのでnoteでは

「本当に気楽に書く。素直に書く。でもちゃんと書く」

という気持ちで書いていこうと思ってます!🍺

長文をここまで読んでくれた方、ありがとうございます!