この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:6
ページ更新者:guest
更新日時:2026-06-11 07:07:02

タイトル: v-bindによるデータ連携
SEOタイトル: Vue.js v-bind 完全ガイド (属性 / クラス / スタイル / Composition API)

この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li><strong><code>v-bind:href="url"</code></strong> = HTML 属性に JS の値をバインド。短縮形は <strong><code>:href="url"</code></strong></li><li>クラスの動的切替: <strong><code>:class="{ active: isActive }"</code></strong> (オブジェクト) / <strong><code>:class="[cls1, cls2]"</code></strong> (配列)</li><li>スタイルの動的切替: <strong><code>:style="{ color: textColor, fontSize: size + "px" }"</code></strong></li><li><strong><code>v-bind="objWithMultipleProps"</code></strong> でオブジェクト全プロパティを一括バインド</li><li><strong>Composition API</strong> では <code>ref</code> / <code>computed</code> の値が <code>:</code> 経由で自動 unwrap</li></ul></td></tr></table>
<h2>v-bind の基本</h2>

<p><code>v-bind</code> は HTML 属性の値を JavaScript 式で動的に決定するための Vue ディレクティブです。短縮形 <code>:</code> が広く使われます。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><template>
    <!-- 完全形 -->
    <a v-bind:href="url">リンク</a>

    <!-- 短縮形 (推奨) -->
    <a :href="url">リンク</a>

    <!-- 複数の属性 -->
    <img :src="imageUrl" :alt="imageAlt" :width="width">

    <!-- 動的な属性名 (Vue 2.6+) -->
    <button :[attrName]="attrValue">動的</button>

    <!-- Boolean 属性 (true なら属性追加、false なら削除) -->
    <button :disabled="isLoading">送信</button>
    <input :readonly="!editable">
</template>

<script setup>
import { ref } from &apos;vue&apos;;
const url = ref(&apos;https://example.com&apos;);
const imageUrl = ref(&apos;/img/logo.png&apos;);
const isLoading = ref(false);
</script></code></pre>
<h2>クラスバインディング</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><template>
    <!-- オブジェクト構文: キー=クラス名、値=真偽値 -->
    <div :class="{ active: isActive, disabled: !enabled }">...</div>

    <!-- 配列構文 -->
    <div :class="[baseClass, themeClass]">...</div>

    <!-- 配列内オブジェクト -->
    <div :class="[baseClass, { active: isActive }]">...</div>

    <!-- 三項演算子 -->
    <div :class="isError ? &apos;text-red&apos; : &apos;text-green&apos;">...</div>

    <!-- computed と組み合わせ -->
    <div :class="classObject">...</div>
</template>

<script setup>
import { ref, computed } from &apos;vue&apos;;

const isActive = ref(true);
const enabled = ref(false);
const baseClass = ref(&apos;btn&apos;);
const themeClass = ref(&apos;btn-primary&apos;);

const classObject = computed(() => ({
    active: isActive.value,
    &apos;text-danger&apos;: hasError.value,
}));
</script></code></pre>
<h2>スタイルバインディング</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><template>
    <!-- オブジェクト構文(キーはキャメルケース or ケバブケース) -->
    <div :style="{ color: textColor, fontSize: size + &apos;px&apos; }">...</div>
    <div :style="{ &apos;background-color&apos;: bg }">...</div>

    <!-- 配列で複数オブジェクト -->
    <div :style="[baseStyles, overrideStyles]">...</div>

    <!-- CSS 変数 (CSS Custom Properties) -->
    <div :style="{ &apos;--main-color&apos;: mainColor }">...</div>

    <!-- ベンダープレフィックス自動付与 -->
    <div :style="{ transform: &apos;translateX(&apos; + offset + &apos;px)&apos; }">...</div>

    <!-- 配列値で fallback -->
    <div :style="{ display: [&apos;-webkit-box&apos;, &apos;-ms-flexbox&apos;, &apos;flex&apos;] }">...</div>
</template>

<script setup>
import { ref } from &apos;vue&apos;;
const textColor = ref(&apos;#333&apos;);
const size = ref(16);
const offset = ref(100);
</script></code></pre>
<h2>オブジェクトを一括バインド</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><template>
    <!-- 個別 -->
    <input :id="form.id" :type="form.type" :value="form.value" :name="form.name">

    <!-- 一括バインド (v-bind に引数なし) -->
    <input v-bind="form">

    <!-- スプレッド的に使える -->
    <BlogPost v-bind="post" />
    <!-- 上記は <BlogPost :id="post.id" :title="post.title" ... /> と等価 -->
</template>

<script setup>
import { ref } from &apos;vue&apos;;
const form = ref({
    id: &apos;username&apos;,
    type: &apos;text&apos;,
    value: &apos;taro&apos;,
    name: &apos;user&apos;,
});

const post = ref({
    id: 1,
    title: &apos;はじめての Vue.js&apos;,
    author: &apos;田中&apos;,
});
</script></code></pre>
<h2>v-bind の修飾子</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>修飾子</th><th>意味</th><th>例</th></tr></thead>
<tbody>
<tr><td><code>.prop</code></td><td>属性ではなく DOM プロパティとしてバインド</td><td><code>:innerHtml.prop="html"</code></td></tr>
<tr><td><code>.attr</code></td><td>明示的に HTML 属性として (Vue 3)</td><td><code>:value.attr="val"</code></td></tr>
<tr><td><code>.camel</code></td><td>ケバブケース属性名をキャメルに</td><td><code>:view-box.camel="box"</code></td></tr>
<tr><td><code>.sync</code> (Vue 2)</td><td>双方向バインド (v-model:propName で代替)</td><td>非推奨</td></tr>
</tbody>
</table>

<h2>Composition API での ref / computed 連携</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript"><script setup>
import { ref, computed, reactive } from &apos;vue&apos;;

// ref: プリミティブの reactive ラッパー
const count = ref(0);
const isAdmin = ref(false);

// テンプレート内では自動 unwrap (.value 不要)
// <p :data-count="count">  ← count.value ではなく count

// computed: 派生値
const doubled = computed(() => count.value * 2);
const labelClass = computed(() => ({
    active: count.value > 0,
    danger: count.value > 100,
}));

// reactive: オブジェクトの reactive ラッパー
const user = reactive({
    name: &apos;田中&apos;,
    age: 30,
});

// 関数で動的な値
function buttonClass(idx) {
    return {
        active: idx === selectedIdx.value,
        first: idx === 0,
    };
}
</script>

<template>
    <p :data-count="count">{{ doubled }}</p>
    <span :class="labelClass">ラベル</span>
    <div :data-user-name="user.name">...</div>
    <button v-for="(item, i) in items" :class="buttonClass(i)">
        {{ item }}
    </button>
</template></code></pre>
<h2>typical use cases</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e8f5e9"><th>シーン</th><th>v-bind の使い方</th></tr></thead>
<tbody>
<tr><td>ボタンの活性状態</td><td><code>:disabled="loading"</code></td></tr>
<tr><td>選択中タブのハイライト</td><td><code>:class="{ active: tab === current }"</code></td></tr>
<tr><td>動的画像</td><td><code>:src="userAvatar"</code></td></tr>
<tr><td>テーマカラー</td><td><code>:style="{ &apos;--brand&apos;: brandColor }"</code></td></tr>
<tr><td>進捗バー</td><td><code>:style="{ width: percent + &apos;%&apos; }"</code></td></tr>
<tr><td>属性ホワイトリスト一括</td><td><code>v-bind="$attrs"</code> (透過)</td></tr>
<tr><td>外部リンク区別</td><td><code>:target="isExternal ? &apos;_blank&apos; : null"</code></td></tr>
</tbody>
</table>

<h2>v-bind と v-on (双方向: v-model)</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><template>
    <!-- v-bind + v-on で擬似 v-model -->
    <input :value="name" @input="name = $event.target.value">

    <!-- v-model はその短縮 (Vue 3) -->
    <input v-model="name">

    <!-- 子コンポーネントへの v-model (Vue 3) -->
    <CustomInput v-model="form.email" v-model:label="form.label" />
    <!-- 子側: defineProps([&apos;modelValue&apos;, &apos;label&apos;]) + emit(&apos;update:modelValue&apos;, val) -->
</template></code></pre>
<h2>よくあるミス</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#fff3e0"><th>ミス</th><th>正解</th></tr></thead>
<tbody>
<tr><td><code>:href="{{ url }}"</code></td><td><code>:href="url"</code> (二重カッコ不要)</td></tr>
<tr><td><code>href="{{ url }}"</code></td><td><code>:href="url"</code> (Mustache は属性に使えない)</td></tr>
<tr><td><code>:class="active"</code> (文字列のつもり)</td><td><code>:class="&apos;active&apos;"</code> または <code>class="active"</code></td></tr>
<tr><td><code>:style="color: red"</code></td><td><code>:style="{ color: &apos;red&apos; }"</code></td></tr>
<tr><td>true/false なのに残る</td><td>Boolean 属性に <code>v-bind</code> を使う</td></tr>
</tbody>
</table>

<h2>FAQ</h2>

<p><strong>Q: <code>v-bind</code> と <code>{{ }}</code> の違いは?</strong><br />
A: <code>{{ }}</code> (Mustache) は<strong>テキストコンテンツ</strong>専用。属性値には使えないので <code>v-bind</code> (短縮 <code>:</code>) を使います。</p>

<p><strong>Q: クラスを class と :class 両方書ける?</strong><br />
A: 可能。Vue は両者をマージします。<code><div class="base" :class="{ active: x }"></code> は OK。</p>

<p><strong>Q: <code>v-bind="$attrs"</code> って何?</strong><br />
A: 親から渡されたが props として宣言していない属性すべてを子要素にパススルー。ラッパーコンポーネントで定番。</p>