Vue.jsが面白くなってきたtomita@atuwebです。

過去にjQueryで実装したフォームをVue.jsで書き直しました。
jQuery実装がVue.jsによってどう改善したか、比較いたします。

完成イメージ

ラジオボタンを操作すると、下の補助入力欄が切り替わるフォームです。

環境

  • PHP 7
  • jQuery 3系
  • Node.js 7系
  • Vue.js 2.2.x
  • Bootstrap

フォームはBootstrapで実装しておりますため、次に掲載いたしますHTMLは長めなことをご容赦ください。

jQuery実装

<div class="form-group">
  <label class="col-lg-2 control-label">Input select</label>
  <div class="col-lg-4">
    <div class="radio">
      <label>
        <input type="radio" name="selector" value="1" checked="">
        Option one is this
      </label>
    </div>
    <div class="radio">
      <label>
        <input type="radio" name="selector" value="2">
        Option two can be something else
      </label>
    </div>
  </div>
</div>

<div class="form-group" id="input1wrap">
  <label for="input1" class="col-lg-2 control-label">Input 1</label>
  <div class="col-lg-4">
    <input type="text" class="form-control" id="input1" placeholder="foo bar">
  </div>
</div>

<div class="form-group" id="input2wrap" style="display:none;">
  <label for="input2" class="col-lg-2 control-label">Input 2</label>
  <div class="col-lg-4">
    <input type="text" class="form-control" id="input2" placeholder="bar buzz">
  </div>
</div>
(function($) {
  $('[name=selector]').change(function() {
    if ($('[name=selector]:checked').val() == 1) {
      $('#input1wrap').show();
      $('#input2wrap').hide();
    } else {
      $('#input1wrap').hide();
      $('#input2wrap').show();
    }
  });
})($);

解説

フォームを切り替えるためのjQuery実装です。

ラジオボタンのchangeをウォッチし、イベントが発生したら(ラジオボタンの操作が発生したら)、チェックされているボタンの値に応じてフォームのshow、hideを切り替えています。

NGポイント

画面遷移時の状態

画面遷移時に2つ目のフォームが表示されないよう、[ style=”display:none” ]を埋め込んでいるのが「古い実装だなー」と感じます。

ラジオボタンの初期値が変化した場合に「どちらのフォームを表示/非表示としておくか」も考えなければなりません。

「フォームを動的に切り替える」という要件に対し、バックエンドも調整しなければならず、フロントエンドとバックエンドで実装が分離 してしまうというバットケースです。

選択肢が増えた場合

ラジオボタンの選択肢が2ならまだ見通しは良いですが、選択肢が3つ、4つと増えた場合、こんな実装になってしまうことがあります。

$('[name=selector]').change(function() {
  var checked = $('[name=selector]:checked').val();
  if (checked == 1) {
    $('#input1wrap').show();
    $('#input2wrap').hide();
    $('#input3wrap').hide();
    $('#input4wrap').hide();
  } else if (checked == 2) {
    $('#input1wrap').hide();
    $('#input2wrap').show();
    $('#input3wrap').hide();
    $('#input4wrap').hide();
  } else if ($checked == 3) {
    $('#input1wrap').hide();
    $('#input2wrap').hide();
    $('#input3wrap').show();
    $('#input4wrap').hide();
  } else {
    $('#input1wrap').hide();
    $('#input2wrap').hide();
    $('#input3wrap').hide();
    $('#input4wrap').show();
  }
});

選択肢の増加によってフォーム切り替えのためのif分岐が増えてしまいました。
イケていないコードの見本ですね。

上の「画面遷移時の初期状態」の実装にも影響しますから、選択肢が増えることによる複雑度の増加は掛け算です。

このようにjQuery実装は全く変更に強くありません

Vue.js実装

<template>
  <form class="form-horizontal">
    <fieldset>
      <div class="form-group">
        <label class="col-lg-2 control-label">Input select</label>
        <div class="col-lg-4">
          <div class="radio">
            <label>
              <input v-model="selector" type="radio" value="1">
              Option one is this
            </label>
          </div>
          <div class="radio">
            <label>
              <input v-model="selector" type="radio" value="2">
              Option two can be something else
            </label>
          </div>
        </div>
      </div>
      <div v-if="selector == 1" class="form-group">
        <label for="input1" class="col-lg-2 control-label">Input 1</label>
        <div class="col-lg-4">
          <input v-model="input1" type="text" class="form-control" id="input1" placeholder="foo bar">
        </div>
      </div>
      <div v-if="selector == 2" class="form-group">
        <label for="input2" class="col-lg-2 control-label">Input 2</label>
        <div class="col-lg-4">
          <input v-model="input2" type="text" class="form-control" id="input2" placeholder="bar buzz">
        </div>
      </div>
    </fieldset>
  </form>
</template>
<script>
export default {
  data() {
    return {
      selector: 1
    }
  }
}
</script>

※1コンポーネントのtemplate, scriptを分けて書いています。

解説

なんということでしょう。
JavaScript側ソースが恐ろしくシンプルになりましたね。

ラジオボタンの選択値

ラジオボタンに[ v-model=”selector” ]を埋め込みました。
ラジオボタンの操作結果がvuejs側のthis.selectorに即反映されます。

フォームの切り替え

inputタグをラップするDivにv-ifを指定しました。
これで「式(v-if=” *** “)が真であれば自身を表示する」という実装が実現できます。

画面遷移時の状態

お任せでOKです。
HTML側に初期状態を設定したとしても、vuejs側が適切に処理してくれます。

選択肢が増えた場合

jQueryと違ってHTMLに要素を足すだけです。
vuejs側のコードにてを加えることはありません。

<form class="form-horizontal">
  <fieldset>
    <div class="form-group">
      <label class="col-lg-2 control-label">Input select</label>
      <div class="col-lg-4">
        <div class="radio">
          <label>
            <input v-model="selector" type="radio" value="1">
            Option one is this
          </label>
        </div>
        <div class="radio">
          <label>
            <input v-model="selector" type="radio" value="2">
            Option two can be something else
          </label>
        </div>
        <div class="radio">
          <label>
            <input v-model="selector" type="radio" value="3">
            Option tree can be something else
          </label>
        </div>
      </div>
    </div>
    <div v-if="selector == 1" class="form-group">
      <label for="input1" class="col-lg-2 control-label">Input 1</label>
      <div class="col-lg-4">
        <input v-model="input1" type="text" class="form-control" id="input1" placeholder="foo bar">
      </div>
    </div>
    <div v-if="selector == 2" class="form-group">
      <label for="input2" class="col-lg-2 control-label">Input 2</label>
      <div class="col-lg-4">
        <input v-model="input2" type="text" class="form-control" id="input2" placeholder="bar buzz">
      </div>
    </div>
    <div v-if="selector == 3" class="form-group">
      <label for="input3" class="col-lg-2 control-label">Input 3</label>
      <div class="col-lg-4">
        <input v-model="input3" type="text" class="form-control" id="input3" placeholder="hoge">
      </div>
    </div>
  </fieldset>
</form>

入力欄の値を取る

各Inputタグにv-modelを埋め込み済みで、これだけで双方向バインディングされます。

<script>
new Vue({
  data() {
    return {
      selector: 1,
      input1: "",
      input2: "",
    }
  },
  methods: {
    hoge() {
        this.input1
        this.input2
    }
  }
});
</script>

jQueryでは都度DOMアクセスする必要があります。

$('#input1').val();
$('#input2').val();

この辺りもVue.jsの便利さが際立ちますね。

おわりに

過去の経験からフロントエンドは食わずな状態が嫌いが続いていましたが、Vue.jsなら楽勝です。
こんなに便利なら楽しく実装できますね。

「過去の経験」についてはこちらをご覧ください。

jQueryで頑張ってしまったことを猛省してLaravel MixでVue.jsを勉強した
豆乳とコストコのマフィンが好きなtomita@atuwebです。 この数年、たいへんなスピードでフロントエンド開発技術が発展し...

Vueが苦手なこともちょっとわかってきましたため、そういった記事も書ければと思います。


スポンサーリンク
ad_336
ad_336
  • このエントリーをはてなブックマークに追加
  • Evernoteに保存Evernoteに保存