Vue.js始めるおれおれアドベントカレンダー2016 – 11日目

昔書いたjQuery版の真似をして一通りやってみます。と言ってもVueはまだよくわかってない感じがあるので何か違う感じあったら教えて欲しい感じです。

前提

  • Vue v2.1.4
  • Vuex v2.0.0

Vuexの state で情報を持ちます。ただの data でもいいよね。

  • state.js
const Vuex = require('vuex')

module.exports = new Vuex.Store({
  state: {
    // ここに値を記述
  }
})
  • App.vue
<form @submit.prevent="form_submit">
  <!-- ここにコントロールを記述 -->
</form>
var store = require('./store.js')

module.exports = {
  data: function () {
    return store.state
  },
  methods: {
    form_submit (event) {
      // …
    }
  }
}

なんか状況によってはめんどくさい場合もあるみたいだけど、今回はそういう状況ではないとします。

凡例

これから記述する各項は

  1. Store
  2. HTML
  3. 情報受け取り

の順にコードを記載します。受け取りはだいたいただ = でもらうだけだけど。

選択肢の持ち方

値はもちろんStoreに持つんだけど、選択肢の方も一緒に管理したいなあと思って、HTMLじゃなくてStoreの方に書いた。(各項参照。)

これってどうだろう? 大丈夫かな?

何かあれば追記します。

テキスト

これが基本パターン。 v-model で紐づけて、普通にそのままもらいます。

module.exports = new Vuex.Store({
  state: {
    text: ''
  }
})
<input v-model="text" type="text" />
const text = this.text

ちなみに v-model.trim="text" にすると前後の空白を取り除いてくれるんだって。

数値

jQueryの方はテキストとして取得してから自分で変換する必要があったけど、Vueは v-model.number で数値として取り扱ってくれる。

module.exports = new Vuex.Store({
  state: {
    number: 0
  }
})
<input v-model.number="number" type="number" />
const number = this.number

ラジオボタン

値自体は単純に選択したラジオボタンの value が文字列として得られる。選択肢もStoreで定義してざらざらーっと v-for で出力。

module.exports = new Vuex.Store({
  state: {
    radio: 'radio1',
    radioOptions: [
      { label: 'ラジオ1', value: 'radio1' },
      { label: 'ラジオ2', value: 'radio2' },
      { label: 'ラジオ3', value: 'radio3' },
      { label: 'ラジオ4', value: 'radio4' },
      { label: 'ラジオ5', value: 'radio5' }
    ],
  }
})
<label v-for="r in radioOptions">
  <input v-model="radio" :value="r.value" type="radio" />
  {{r.label}}
</label>
const radio = this.radio

チェックボックス

ラジオボタンと同じく選択肢のラベルもStoreに設置した。値の取得がちょっと面倒。

module.exports = new Vuex.Store({
  state: {
    checkboxes: [
      { label: 'チェック1', value: 'check1', checked: false },
      { label: 'チェック2', value: 'check2', checked: false },
      { label: 'チェック3', value: 'check3', checked: false },
      { label: 'チェック4', value: 'check4', checked: false },
      { label: 'チェック5', value: 'check5', checked: false }
    ],
  }
})
<label v-for="c in checkboxes">
  <input v-model="c.checked" type="checkbox" />
  {{c.label}}
</label>
const checkboxes = this.checkboxes
  .filter(v => v.checked)
  .map(v => v.value)
  // => ex: [ 'check1', 'check2' ]

これで通常のフォーム送信時と同様に、選択したチェックボックスの value が配列で受け取れる。

他のパターンも考えられそう。

全体を真偽値として受け取る

ならこう。

const checkboxes = this.checkboxes
  .reduce((o, v) => { o[v.value] = v.checked; return o }, {})
  // => ex: { check1: true, check2: true, check3: false }

オフの状態の情報も得られるので、こっちの方が何かと便利そうな気はする。

最初からただの真偽値として扱う

ならこう。

module.exports = new Vuex.Store({
  state: {
    check1: false,
    check2: false
  }
})
<label><input v-model="check1" type="checkbox" /> チェック1</label>
<label><input v-model="check2" type="checkbox" /> チェック2</label>
const checkboxes = {
  check1: this.check1,
  check2: this.check2
}

まあこれが一番単純でわかりやすい。複数選択じゃなくてオンオフ(規約に同意、とか)はもちろんこちらで。

セレクトボックス(単数)

ラジオボタンと同じく、選択と選択肢をそれぞれ持ち、選択結果は value の値。ただし v-forv-model を書く要素は逆になる。

module.exports = new Vuex.Store({
  state: {
    select: 'select1',
    selectOptions: [
      { label: 'セレクト1', value: 'select1' },
      { label: 'セレクト2', value: 'select2' },
      { label: 'セレクト3', value: 'select3' },
      { label: 'セレクト4', value: 'select4' },
      { label: 'セレクト5', value: 'select5' }
    ]
  }
})
<select v-model="select">
  <option v-for="s in selectOptions" :value="s.value">
    {{s.label}}
  </option>
</select>
const select = this.select

セレクトボックス(複数)

配列になる以外は一緒。

module.exports = new Vuex.Store({
  state: {
    multiSelect: [],
    multiSelectOptions: [
      { label: 'セレクト1', value: 'select1' },
      { label: 'セレクト2', value: 'select2' },
      { label: 'セレクト3', value: 'select3' },
      { label: 'セレクト4', value: 'select4' },
      { label: 'セレクト5', value: 'select5' }
    ]
  }
})
<select v-model="multiSelect">
  <option v-for="s in multiSelectOptions" :value="s.value">
    {{s.label}}
  </option>
</select>
const multiSelect = this.multiSelect

ファイル

HTML5であれこれする必要がある。もちろんその橋渡しがVueで便利にやれるんだろうけど。

→書いた: ファイルを読み込んでプレビュー表示してみる。(Vue.js始めるおれおれアドベントカレンダー2016 – 12日目)

おしまい

もっと良さそうな書き方あれば教えてください。

参考