Vueのデータバインディングについて
Vue.jsにおけるバインド(bind)とは、一言で言うと「データと見た目(DOM)を結びつける(連携させる)仕組み」のことです。これをデータバインディングと呼びます。
データバインディングを使うと、JavaScriptのデータ(変数やオブジェクト)が変更されたときに、Webページの表示が自動的に更新されるようになります。これにより、DOMを直接操作するコードを書く手間が省け、コードがシンプルで分かりやすくなります。
主要なバインドにはいくつか種類があります。
テキストのバインド(マスタッシュ構文)
最も基本的なバインド方法で、{{ }}
(マスタッシュ構文)を使ってデータをテキストとして表示します。
データのmessage
が変更されると、<h1>
タグの中身も自動的に更新されます。
コード例:
<div id="app">
<h1>{{ message }}</h1>
</div>
<script>
const { createApp } = Vue
createApp({
data() {
return {
message: 'こんにちは、Vue!'
}
}
}).mount('#app')
</script>
表示結果:
こんにちは、Vue!
属性のバインド (v-bind
)
v-bind
は、HTML要素の属性(attribute)を Vue インスタンスのデータと動的に連携させるためのディレクティブです。これにより、データの変更に応じて要素の見た目や動作をリアルタイムに制御できます。
一般的には省略形の :
(コロン) がよく使われます。例えば、v-bind:href
は :href
と同じ意味です。
基本的な使い方
属性値にVueのデータプロパティを割り当てる最もシンプルな使い方です。
<div id="app">
<img :src="imageUrl" alt="Vue Logo">
<button :disabled="isButtonDisabled">クリックしてね</button>
</div>
<script>
const { createApp } = Vue
createApp({
data() {
return {
imageUrl: 'https://vuejs.org/images/logo.png',
isButtonDisabled: true // trueだとボタンは無効になる
}
}
}).mount('#app')
</script>
isButtonDisabled
の値を false
に変更すると、ボタンがクリックできるようになります。
クラスのバインディング
v-bind
の中でも特に強力で頻繁に使われるのが、class
属性の動的な操作です。オブジェクト構文と配列構文の2つの方法があります。
1. オブジェクト構文
{ クラス名: 真偽値 }
の形式で記述します。真偽値が true
の場合にのみ、そのクラスが要素に適用されます。
コード例:
<div id="app">
<div :class="{ active: isActive, 'text-danger': hasError }">
このテキストの色やスタイルが変わります
</div>
<button @click="toggleActive">アクティブ切り替え</button>
<button @click="toggleError">エラー切り替え</button>
</div>
<style>
.active {
font-weight: bold;
color: blue;
}
.text-danger {
background-color: #fdd;
border: 1px solid red;
}
</style>
<script>
// ... Vueインスタンスの作成
createApp({
data() {
return {
isActive: true,
hasError: false
}
},
methods: {
toggleActive() { this.isActive = !this.isActive },
toggleError() { this.hasError = !this.hasError }
}
}).mount('#app')
</script>
この方法を使うと、複数のクラスの有無をそれぞれのデータプロパティで個別に管理できるため、非常に便利です。
2. 配列構文
複数のクラスをリストとして適用したい場合に使用します。
コード例:
<div id="app">
<div :class="[activeClass, errorClass]">テキスト</div>
<p :class="[isActive ? activeClass : '', errorClass]">条件付きテキスト</p>
</div>
<script>
// ... Vueインスタンスの作成
createApp({
data() {
return {
activeClass: 'active',
errorClass: 'text-danger',
isActive: true
}
}
}).mount('#app')
</script>
配列構文とオブジェクト構文は組み合わせて使うこともできます。
<div :class="[{ active: isActive }, errorClass]">...</div>
スタイルのバインディング
インラインの style
属性を動的に操作する場合にも v-bind
を使います。こちらもオブジェクト構文と配列構文があります。
1. オブジェクト構文
CSSプロパティをキーとするオブジェクトを渡します。プロパティ名はキャメルケース (fontSize
) またはケバブケース ('font-size'
) で指定できます。
コード例:
<div id="app">
<p :style="{ color: activeColor, fontSize: fontSize + 'px' }">
このテキストのスタイルはデータで管理されています
</p>
<input type="range" v-model="fontSize" min="10" max="40">
</div>
<script>
// ... Vueインスタンスの作成
createApp({
data() {
return {
activeColor: 'red',
fontSize: 16
}
}
}).mount('#app')
</script>
スライダーを動かすと、リアルタイムで文字の大きさが変わります。
2. 配列構文
複数のスタイルオブジェクトをマージ(結合)して適用できます。
<div id="app">
<p :style="[baseStyles, overridingStyles]">
複数のスタイルオブジェクトを適用
</p>
</div>
<script>
// ... Vueインスタンスの作成
createApp({
data() {
return {
baseStyles: {
color: 'white',
backgroundColor: 'black',
padding: '10px'
},
overridingStyles: {
fontWeight: 'bold',
border: '2px solid orange'
}
}
}
}).mount('#app')
</script>
動的な引数
v-bind
の少し高度な使い方として、バインドする属性名自体を動的にすることができます。角括弧 []
を使って属性名をデータで指定します。
コード例:
<div id="app">
<p>
<a :[attributeName]="url">動的な属性を持つリンク</a>
</p>
<button @click="changeAttribute">属性を変更</button>
</div>
<script>
// ... Vueインスタンスの作成
createApp({
data() {
return {
attributeName: 'href',
url: 'https://jp.vuejs.org/'
}
},
methods: {
changeAttribute() {
// 'href' と 'title' を交互に切り替える
this.attributeName = this.attributeName === 'href' ? 'title' : 'href'
}
}
}).mount('#app')
</script>
ボタンをクリックすると、リンクが機能したり、マウスオーバーでツールチップが表示されたりする動作が切り替わります。
まとめ
v-bind
(または :
) は、Vue.jsでUIを動的に制御するための基本かつ非常に重要な機能です。
-
基本的な属性:
src
,href
,disabled
などをデータと連動させます。 - クラスの操作: オブジェクトや配列を使い、複雑なCSSクラスの適用ロジックを簡潔に記述できます。
- スタイルの操作: インラインスタイルをデータで管理し、動的なデザイン変更を容易にします。
- 動的な引数: 属性名自体もデータで管理できるため、高い柔軟性を持ちます。
特にクラスとスタイルのバインディングは、インタラクティブなUIを作成する上で必須のテクニックとなります。
フォーム入力のバインド (v-model
)
v-model
は、フォームの入力要素 (<input>
, <textarea>
, <select>
) やコンポーネントと、Vueインスタンスの**データを双方向で結びつける(バインドする)**ためのディレクティブです。
双方向データバインディングとは?
v-model
の最大の特徴は「双方向」である点です。
-
データ → 表示: JavaScriptのデータ (
data
) を変更すると、フォームの表示(値)が自動的に更新されます。 -
表示 → データ: ユーザーがフォームに入力・操作すると、その内容が自動的にJavaScriptのデータ (
data
) に反映されます。
この仕組みにより、面倒なDOM操作やイベントリスナーの設定をすることなく、フォームの状態をデータとして簡単に管理できます。
要素別の使い方
v-model
は、使用するフォーム要素によって少しだけ挙動が変わります。
1. テキスト入力 (<input type="text">
, <textarea>
)
最も基本的な使い方です。入力された文字列がそのままデータに反映されます。
<div id="app">
<input type="text" v-model="message" placeholder="メッセージを入力">
<p>入力内容: {{ message }}</p>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
message: ''
}
}
}).mount('#app');
</script>
入力ボックスに文字をタイプすると、<p>
タグの表示がリアルタイムで更新されていきます。
2. チェックボックス (<input type="checkbox">
)
単一の場合:
単一のチェックボックスは、真偽値(true
/false
)を扱います。
<div id="app">
<input type="checkbox" id="agreement" v-model="agreed">
<label for="agreement">利用規約に同意します</label>
<p>同意の状態: {{ agreed }}</p>
</div>
<script>
// ...
createApp({
data() { return { agreed: false } }
}).mount('#app');
</script>
チェックを入れると agreed
は true
に、外すと false
になります。
複数の場合:
複数のチェックボックスを同じデータ(配列)にバインドすることで、選択された値をまとめて管理できます。
<div id="app">
<p>好きなフルーツを選んでください:</p>
<input type="checkbox" id="apple" value="りんご" v-model="checkedFruits">
<label for="apple">りんご</label>
<input type="checkbox" id="orange" value="みかん" v-model="checkedFruits">
<label for="orange">みかん</label>
<input type="checkbox" id="grape" value="ぶどう" v-model="checkedFruits">
<label for="grape">ぶどう</label>
<p>選択中のフルーツ: {{ checkedFruits }}</p>
</div>
<script>
// ...
createApp({
data() { return { checkedFruits: [] } } // 配列で初期化
}).mount('#app');
</script>
チェックを入れた項目の value
属性の値が、checkedFruits
配列に追加/削除されます。
3. ラジオボタン (<input type="radio">
)
複数の選択肢から一つだけを選ぶ場合に使います。選択されたラジオボタンの value
属性の値がデータに格納されます。
<div id="app">
<p>配送方法:</p>
<input type="radio" id="mail" value="メール便" v-model="shippingMethod">
<label for="mail">メール便</label>
<input type="radio" id="express" value="宅配便" v-model="shippingMethod">
<label for="express">宅配便</label>
<p>選択中の配送方法: {{ shippingMethod }}</p>
</div>
<script>
// ...
createApp({
data() { return { shippingMethod: 'メール便' } }
}).mount('#app');
</script>
4. セレクトボックス (<select>
)
ドロップダウンリストの選択値をバインドします。選択された <option>
の value
属性の値がデータに格納されます。
<div id="app">
<select v-model="selectedCategory">
<option disabled value="">カテゴリーを選択してください</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<p>選択中のカテゴリー: {{ selectedCategory }}</p>
</div>
<script>
// ...
createApp({
data() { return { selectedCategory: '' } }
}).mount('#app');
</script>
v-modelの修飾子(Modifiers)
v-model
の動作を細かく調整するための修飾子があります。
修飾子 | 説明 | 使用例 |
---|---|---|
.lazy |
input イベントごとではなく、change イベントが起きた後(フォーカスが外れた時など)にデータを同期させます。 |
<input v-model.lazy="msg"> |
.number |
ユーザーの入力値を自動的に数値 (Number ) 型に変換します。 |
<input v-model.number="age"> |
.trim |
ユーザー入力の前後の空白を自動的に除去します。 | <input v-model.trim="username"> |
これらの修飾子は、v-model.lazy.trim="text"
のように繋げて使うこともできます。
v-model
の仕組み(内部的な動き)
v-model
は、実は **v-bind
と v-on
を組み合わせた糖衣構文(シンタックスシュガー)**です。つまり、内部的には以下のコードと同じ働きをしています。
<input v-model="searchText">
<input
:value="searchText"
@input="searchText = $event.target.value"
>
-
:value="searchText"
(v-bind
): データ (searchText
) をinput
要素のvalue
属性にバインドします(データ → 表示)。 -
@input="..."
(v-on
):input
イベントが発生するたび(文字が入力されるたび)に、イベントオブジェクト ($event
) から入力値を取得し、データ (searchText
) に代入します(表示 → データ)。
この仕組みを理解しておくと、後述するカスタムコンポーネントで v-model
を使う際に非常に役立ちます。
カスタムコンポーネントでの v-model
v-model
は自作のコンポーネントに対しても使用でき、再利用性の高い入力コンポーネントを作成するのに非常に便利です。
Vue 3では、コンポーネントで v-model
を使うと、デフォルトで以下のようになります。
-
プロパティ(props):
modelValue
という名前のプロパティを受け取ります。 -
イベント(emits): 値を変更するとき、
update:modelValue
という名前のイベントを親に通知(emit)します。
例: カスタム入力コンポーネント
CustomInput.js
(子コンポーネント)
app.component('custom-input', {
props: ['modelValue'],
emits: ['update:modelValue'],
template: `
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
>
`
})
親コンポーネントでの使用
<div id="app">
<custom-input v-model="parentMessage"></custom-input>
<p>親のデータ: {{ parentMessage }}</p>
</div>
<script>
// ...
createApp({
data() { return { parentMessage: '初期値' } }
}).mount('#app');
</script>
このように、親子間でのデータの受け渡しが v-model
一つで非常にシンプルに記述できます。
イベントのバインド (v-on
)
v-on
は、DOMイベント(ユーザーの操作など)を監視し、イベントが発生した時に指定されたJavaScriptコードを実行するためのディレクティブです。
一般的には、より短く記述できる省略形の @
が広く使われます。例えば、v-on:click
は @click
と全く同じ意味です。
基本的な使い方
v-on
は、@
の後にイベント名(click
, submit
, input
など)を続け、実行したい処理を値として指定します。
1. メソッドを呼び出す
最も一般的な使い方です。methods
オプションに定義した関数(メソッド)を呼び出します。
<div id="app">
<p>カウント: {{ count }}</p>
<button @click="increment">カウントアップ</button>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
count: 0
}
},
methods: {
// ボタンがクリックされたときに実行される処理
increment() {
this.count++;
console.log('カウントが1増えました。');
}
}
}).mount('#app');
</script>
2. インラインで処理を記述する
非常にシンプルな処理であれば、methods
を定義せずに直接テンプレート内に記述することも可能です。
<div id="app">
<p>カウント: {{ count }}</p>
<button @click="count++">カウントアップ</button>
</div>
メソッドに引数を渡す
イベントハンドラに独自の引数を渡すことができます。
1. 独自の引数を渡す
メソッド名の後の ()
内に引数を指定します。
<div id="app">
<button @click="greet('Hello')">挨拶する</button>
</div>
<script>
// ...
createApp({
methods: {
greet(message) {
alert(message);
}
}
}).mount('#app');
</script>
2. 元のDOMイベントオブジェクトも使う
独自の引数を使いつつ、元のDOMイベントオブジェクトにもアクセスしたい場合は、特別な変数 $event
を引数として渡します。
<div id="app">
<button @click="warn('ボタンがクリックされました', $event)">警告を表示</button>
</div>
<script>
// ...
createApp({
methods: {
warn(message, event) {
// event はネイティブの DOM イベントオブジェクト
if (event) {
event.preventDefault(); // イベントのデフォルトの動作をキャンセル
}
alert(message);
console.log(event.target.tagName); // 'BUTTON' が出力される
}
}
}).mount('#app');
</script>
イベント修飾子(Event Modifiers)
v-on
には、イベントの動作を細かく制御するための「修飾子」があります。イベント名の後にドット .
をつけて記述します。これらを使うことで、event.preventDefault()
のような定型コードを書く手間が省けます。
修飾子 | 説明 |
---|---|
.stop |
イベントの伝播を停止します (event.stopPropagation() )。 |
.prevent |
要素のデフォルトの動作をキャンセルします (event.preventDefault() )。 |
.capture |
イベントをキャプチャフェーズで処理します。 |
.self |
イベントがその要素自身から発生した場合のみハンドラをトリガーします(子要素からの伝播は無視)。 |
.once |
ハンドラを一度だけ実行し、その後はトリガーされません。 |
.passive |
イベントのデフォルト動作を妨げないことをブラウザに伝え、特にスクロールイベントなどでパフォーマンスを向上させます。 |
使用例: .prevent
と .stop
<form @submit.prevent="onSubmit">
<button type="submit">送信</button>
</form>
<div @click="handleParentClick">
親要素
<button @click.stop="handleChildClick">子要素 (クリックしても親のイベントは発生しない)</button>
</div>
キー修飾子(Key Modifiers)
キーボードイベント (@keydown
, @keyup
など) を扱う際に、特定のキーが押された時だけハンドラを実行するように指定できます。
一般的なキーエイリアス:
.enter
.tab
-
.delete
(Delete
とBackspace
の両方のキーを捕捉) .esc
.space
-
.up
,.down
,.left
,.right
使用例:
<div id="app">
<input @keydown.enter="addItem" v-model="newItem" placeholder="アイテムを追加してEnter">
</div>
これにより、「もし event.key
が 'Enter' なら...」といった条件分岐を書く必要がなくなります。
カスタムイベントの待受
v-on
(または @
) は、子コンポーネントから発行(emit)されたカスタムイベントを親コンポーネントで受け取るためにも使われます。これはコンポーネント間の通信で非常に重要な役割を果たします。
ChildComponent.js
(子コンポーネント)
app.component('child-component', {
emits: ['response'], // 発行するイベント名を明記
template: `
<button @click="$emit('response', '子からのメッセージです!')">
親にイベントを通知
</button>
`
})
親コンポーネントでの使用
<div id="app">
<child-component @response="handleResponse"></child-component>
<p>{{ childMessage }}</p>
</div>
<script>
// ...
createApp({
data() {
return { childMessage: '' }
},
methods: {
handleResponse(payload) {
this.childMessage = payload; // 子から受け取ったデータを更新
}
}
}).mount('#app');
</script>
このように、v-on
はDOMイベントからコンポーネント間の通信まで、Vueアプリケーションのあらゆる「イベント」を扱うための統一されたインターフェースを提供します。
まとめ
バインドの種類 | ディレクティブ(省略形) | 説明 | 用途 |
---|---|---|---|
テキスト | {{ }} |
データをテキストとして表示する(単方向) | 画面へのデータ表示 |
属性 |
v-bind (: ) |
HTMLの属性値とデータを結びつける(単方向) |
src やclass の動的な変更 |
フォーム入力 | v-model |
フォーム要素とデータを双方向で結びつける | ユーザー入力のハンドリング |
イベント |
v-on (@ ) |
DOMイベントとメソッドを結びつける | クリックなどのユーザー操作への対応 |
これらのバインドを使いこなすことで、Vue.jsのリアクティブ(反応的)なWebアプリケーションを効率的に開発できます。