【vue】 v-bindでvueの値をHTMLとやり取りする方法

vueでは、vueの値をHTMLの属性に設定したり、入力フォームに入れた値をvueの値に反映させるにはv-bindv-modelを用います。

v-bindは、やり取りというよりはvueからDOMへの一方向の押しつけ、v-modelは相互にやり取りできます。

v-bindでvueの値をHTMLの属性に使う

要素の属性にv-bind:をつけると、vueの値をタグの属性に設定することができます。

例えば、aタグのhrefに設定する場合、

Vue.createApp({
    data() {
        protocol: "https://",
        domain: "example.com",
    }
});
<!-- hrefにhttps://example.com が設定される -->
<a v-bind:href="protocol + domain">...</a>

値を使う際にthisは不要です。

のようになります。v-bind:は単に:と省略できるので、

<a :href="protocol + domain">...</a>

のように、:属性と書くことができます。

See the Pen vue v-bind by Totori (@souki202) on CodePen.

ここで、中に入れるのは普通のJavascriptの式なので、文字列を入れる際はシングルクォーテーションで囲む必要があります。

<a :href="'https://' + domain">...</a>
<!-- もちろん配列なども普通に使える -->
<a :href="'https://' + domain[3]">...</a>
<a :href="'https://example.com'"></a>

特に、上の例の3つ目のように文字列だけの場合、v-bindを付けていることを忘れてシングルクォーテーション入れ忘れ、エラーとなったり動作しない場合があるので注意が必要です。 (v-bindしなければよいだけの話ですが…)

v-modelで入力値をvueとやり取り

v-modelを用いることで、HTML側のinputの値などとvueの値を相互にやり取りできます。

文字入力欄

v-model="変数"のように書きます。

<input type="text" v-model="value">
<input type="date" v-model="foo.date">
const app = Vue.createApp({
    data() {
        return {
            value: "foo",

            foo: {
                date: "2022-02-20",
            },
        }
    },
});

とすると、1つ目の入力欄に文字列を入れると、vue側のvalueという変数に、2つ目の入力欄に文字列を入れると、vue側のfoo.dateという変数に入力した値が格納されます。

何か同期ボタンのようなものはなく、入力すると自動的に同期されます。

さらに、vue側の値を更新すると、入力欄に入力されている値も更新されます。

See the Pen vue v-model by Totori (@souki202) on CodePen.

ラジオボタン

ラジオボタンの場合、一連の同じnameのラジオボタンには同じv-modelを入れます。

<input type="radio" name="r1" value="ボタン1" v-model="btnValue">
<input type="radio" name="r1" value="ボタン2" v-model="btnValue">
<input type="radio" name="r1" value="ボタン3" v-model="btnValue">

ラジオボタンは、一連のセットの中で1つしか選べません。そのため、同期先の変数も一つで良いです。

変数には、選択したボタンに設定されているvalue属性の値が使われます。もちろん、valuev-bindしていても問題ありません。

See the Pen vue v-model radio by Totori (@souki202) on CodePen.

もし最初からラジオボタンを選択した状態にしたい場合、vue側の変数に該当のvalueを入れます。これは、変数に代入したときも反映されます。

const app = Vue.createApp({
    data() {
        return {
            v: "ボタン2", // 上の例の2番目のラジオボタンを選択した状態になる
        }
    },
    methods: {
        selectRadio() {
            this.v = "ボタン1"; // ボタン1が選択される
        }
    }
});

チェックボックス(1つ)

1つのチェックボックスの場合、valueの設定に関係なくvueの変数にはtrueかfalseが入ります。

例えば、

<input type="checkbox" name="r1" value="ボタン1" v-model="v">
const app = Vue.createApp({
    data() {
        return {
            : "",
        }
    },
});

というコードがあった場合、ボタンにチェックを入れてもvに代入されるのはボタン1ではなくtrueです。

See the Pen vue v-model checkbox by Totori (@souki202) on CodePen.

ラジオボタンの時と同様に、

data() {
    return {
        v: true,
    }
},

とすれば最初からチェックが入った状態になります。

この書き方は、チェックボックスが1つのときだけに可能な特殊な例と言えます。

vue側でv: []のように配列にすれば、1個だけの場合でも下の複数パターンと同じ挙動にすることができます。

チェックボックス(複数)

複数のチェックボックスに対して同じv-modelを設定し、かつvue側でv-modelに入れる変数を配列とした場合、配列にはチェックが入った項目のvalueが入ります。

例えば、

<input type="checkbox" value="ボタン1" v-model="v">
<input type="checkbox" value="ボタン2" v-model="v">
<input type="checkbox" value="ボタン3" v-model="v">

の3つのうち、2つ目と3つ目にチェックを入れると、vueには["ボタン2", "ボタン3"]という値が入ります。

値は、チェックを入れると最後尾に入ります。ボタンの並び順ではありません。

See the Pen by Totori (@souki202) on CodePen.

今までと同様に、valueの値を設定すればチェックボックスにも反映されます。

const app = Vue.createApp({
    data() {
        return {
            v: ["ボタン1", "ボタン3"], // ボタン1と3が選択された状態になる
        }
    },
});

セレクト

選択中のoptionの値が入ります。ここで、optionvalueが設定されていればvalueが、設定されていなければ表示する値が利用されます。

v-modelselectタグ側に<select v-model="varname">...</select>のように設定します。

例えば、

<select v-model="v">
    <option value="hoge">aaa</option>
    <option>fuga</option>
    <option>foobar</option>
</select>

の3項目だった場合、aaaを選択時はhogeが変数vに入ります。fugaを選択時はvalueが無いため、表示する文字そのものであるfugaが入ります。

See the Pen vue v-model select by Totori (@souki202) on CodePen.

セレクト(複数)

チェックボックスのときと同じように、vue側には配列を設定します。値は、普通のselectと同じように、valueがあればその値が、なければ表示する文字が値として入ります。

<select v-model="v">
    <!-- ... -->
</select>
const app = Vue.createApp({
    data() {
        return {
            v: [],
        }
    },
});

See the Pen vue v-model select2 by Totori (@souki202) on CodePen.

selectで複数選択するには、タグ側にmultiple属性を付けます。<select multiple></select>

選択時は、ドラッグする、Ctrlキーを押しながら選択する、で複数選択できます。

v-bindとv-modelをあわせる

例えば, ラジオボタンのvalueをv-bindで、チェックが入ったらその値をv-modelに入れたい場合です。

この場合も今までの設定と同じです。ただvalue:valueになるだけです。

<input type="radio" name="r1" id="radio1" :value="radioValue1" v-model="v">
const app = Vue.createApp({
    data() {
        return {
            radioValue1: "foobar",
            v: "",
        }
    },
});

このようにすると、inputvaluefoobarになるため、ラジオボタンを選択すると"foobar"という値がvに入ります。

See the Pen vue v-model radio2 by Totori (@souki202) on CodePen.

リストとv-model

配列を使ってv-forを用いて入力欄を作成する時、普通のjsのようなfor-inをしてしまうと、入力してもvueの変数に反映されません。代入された側の変数と元の変数に繋がりがないためです。

<!-- 駄目なパターン -->
<div v-for="memo in memos">
    <!-- v-forで新しく作った変数にv-modelを設定している -->
    <input type="text" v-model="memo">
</div>

そのため、インデックスを使用して元の変数にアクセスするべきです。

<!-- 良いパターン -->
<div v-for="(memo, i) in memos">
    <!-- vueにある変数にv-modelを指定している -->
    <input type="text" v-model="memos[i]">
</div>

See the Pen Untitled by Totori (@souki202) on CodePen.

修飾子で値のやりとりを制御

lazy

textやtextareaのinputで、inputイベントではなくchangeイベントが走ったときに適用されるようにできます。

<textarea v-model.lazy="v" cols="30" rows="10"></textarea>

これにより、v-modelに設定した値の更新回数が減少します。入力が完了したら通信してチェックするなど、更新時に重い処理をしたい場合に最適です。

number

inputtype="number"としても文字列がv-modelの変数に入りますが、これを自動的に数値に変換できます。

<input type="number" v-model.number="v">

つまり、元のままでは、100を入力してもvueに"100"が入ってしまうということです。

trim

文字列の最初と最後の空白を自動的に削除します。

<input type="text" v-model.trim="v">

v-bindとv-modelの違い

v-bindは、vueからDOMへの一方通行です。inputの値を変えてもvue側の値は変わりません。

v-modelは、双方に反映されます。vueの値を設定できますし、inputの入力を変えたりすればvue側の値も変わります。しかし、inputやselectのような入力欄系のものにしか使用できません。

まとめ

v-bindとv-modelは似ていますが、全く異なるものです。特に、inputに:valueとしても、入力時にvue側に値が反映されないということに注意が必要です。

inputなどに入力した値との同期にはv-modelを、vueの値をタグの属性に設定したいならv-bindと覚えておきましょう!

v-bind v-model thumb

役に立ったらシェアしよう!