Vue.js、Vue.jsのデータバインディングやテンプレート構文を解説

javascript
この記事は約19分で読めます。

テンプレート構文の基本

Vue.jsのテンプレート構文は、HTMLの見た目を保ちながら動的なUIを構築するための強力なツールです。ここでは、データバインディング、属性バインディング、イベントハンドリングについて詳しく解説します。

データバインディング

データバインディングは、テンプレートとVueインスタンスのデータを連携させる仕組みです。これにより、データの変更が即座にUIに反映されます。

{{ }}(Mustache記法)の使い方

  • Mustache記法を使うと、Vueインスタンスのデータプロパティをテンプレート内に埋め込むことができます。
<div id="app">
  <p>{{ message }}</p>
</div>
HTML
const app = Vue.createApp({
  data() {
    return {
      message: 'こんにちは、Vue.js!'
    };
  }
});
app.mount('#app');
JavaScript

上記の例では、messageの値がテンプレートに表示されます。

属性バインディング

HTML属性に動的な値を適用する場合には、v-bindディレクティブを使用します。

v-bindの基本

  • v-bindを使うことで、属性値にVueインスタンスのデータをバインドできます。
<div id="app">
  <a v-bind:href="url">リンク</a>
</div>
HTML
const app = Vue.createApp({
  data() {
    return {
      url: 'https://example.com'
    };
  }
});
app.mount('#app');
JavaScript

ショートハンド(:属性名)の使い方

  • v-bindは頻繁に使うため、ショートハンドで記述できます。v-bind:hrefは:hrefと省略可能です。
<a :href="url">リンク</a>
HTML
  • Mustache記法 ({{ }})
    • テンプレート内でデータを表示する最も基本的な方法。
    • 例: <p>{{ message }}</p> → messageの値が表示される。
  • 属性バインディング (v-bind)
    • HTML属性にデータを動的にバインドする。
    • ショートハンド: :属性名(例: <a :href=”url”>)。

イベントハンドリング

ユーザーアクションを検知して処理を実行するには、v-onディレクティブを使用します。

v-onによるイベントリスナーの設定

  • v-onを使ってイベントリスナーを設定します。
<div id="app">
  <button v-on:click="greet">クリックして挨拶</button>
</div>
HTML
const app = Vue.createApp({
  data() {
    return {
      message: 'こんにちは!'
    };
  },
  methods: {
    greet() {
      alert(this.message);
    }
  }
});
app.mount('#app');
JavaScript

ショートハンド(@イベント名)の使い方

  • v-onもショートハンドで記述可能です。v-on:clickは@clickと省略できます。
<button @click="greet">クリックして挨拶</button>
HTML

イベント修飾子

イベント修飾子を使うと、イベントの挙動を簡単に制御できます。

.prevent

デフォルトのイベント動作をキャンセルします。

<form @submit.prevent="submitForm">
  <button type="submit">送信</button>
</form>
HTML

.stop

イベントの伝播を停止します。

<div @click="parentClick">
  <button @click.stop="childClick">子要素をクリック</button>
</div>
HTML
  • v-onディレクティブ
    • イベントリスナーをテンプレートに設定する方法。
    • 例: <button v-on:click=”doSomething”>。
    • ショートハンド: @イベント名(例: <button @click=”doSomething”>)。
  • イベント修飾子
    • .prevent: デフォルト動作をキャンセル。
    • .stop: イベントの伝播を停止。

条件付きレンダリング

UIの表示や非表示を条件に応じて制御する方法を提供します。

v-if, v-else-if, v-else

条件に応じて要素をレンダリングします。

<div id="app">
  <p v-if="status === 'loading'">読み込み中...</p>
  <p v-else-if="status === 'success'">データ取得成功!</p>
  <p v-else>エラーが発生しました。</p>
</div>
HTML
const app = Vue.createApp({
  data() {
    return {
      status: 'loading'
    };
  }
});
app.mount('#app');
JavaScript

v-show

要素を非表示にする際にCSSのdisplayプロパティを変更します。

<div id="app">
  <p v-show="isVisible">このテキストは表示されます。</p>
  <button @click="isVisible = !isVisible">表示/非表示を切り替える</button>
</div>
HTML
const app = Vue.createApp({
  data() {
    return {
      isVisible: true
    };
  }
});
app.mount('#app');
JavaScript

v-ifとv-showの違い

  • v-if・v-else-if・v-else
    • 条件に基づき要素をレンダリング。
    • 例: <p v-if=”isActive”>アクティブです</p>。
  • v-show
    • 要素の表示・非表示をCSSのdisplayプロパティで制御。
  • 違い
    • v-if: DOMの追加/削除。初期レンダリングに適している。
    • v-show: DOMを保持したまま切り替え。頻繁な表示切り替えに適している。

v-forの使い方とキー属性の重要性、リストレンダリング

リストデータをレンダリングする際に使用するのがv-forディレクティブです。繰り返し処理を簡潔に記述できます。

<div id="app">
  <ul>
    <li v-for="item in items" :key="item.id">{{ item.name }}</li>
  </ul>
</div>
HTML
const app = Vue.createApp({
  data() {
    return {
      items: [
        { id: 1, name: 'アイテム1' },
        { id: 2, name: 'アイテム2' },
        { id: 3, name: 'アイテム3' }
      ]
    };
  }
});
app.mount('#app');
JavaScript
  • ポイント
    • item in itemsで配列itemsをループ処理します。
    • :key属性は、リスト項目が一意に識別されるようにするために必須です。

キー属性の重要性

  • 再レンダリングの最適化: :keyが設定されていると、Vueはリスト項目を効率的に再利用します。
  • 一意性の確保: キーには一意な値(例: IDやインデックス)を設定します。
<li v-for="(item, index) in items" :key="index">{{ item.name }}</li>
HTML

※ただし、インデックスは推奨されません。一意なIDを使うべきです。

ネストされたリストの実装方法

Vue.jsでは、リスト内にさらにリストをネストして表示することも簡単です。

ネストリストの例

<div id="app">
  <ul>
    <li v-for="category in categories" :key="category.id">
      {{ category.name }}
      <ul>
        <li v-for="subItem in category.items" :key="subItem.id">
          {{ subItem.name }}
        </li>
      </ul>
    </li>
  </ul>
</div>
HTML
const app = Vue.createApp({
  data() {
    return {
      categories: [
        {
          id: 1,
          name: 'カテゴリ1',
          items: [
            { id: 101, name: 'サブアイテム1-1' },
            { id: 102, name: 'サブアイテム1-2' }
          ]
        },
        {
          id: 2,
          name: 'カテゴリ2',
          items: [
            { id: 201, name: 'サブアイテム2-1' },
            { id: 202, name: 'サブアイテム2-2' }
          ]
        }
      ]
    };
  }
});
app.mount('#app');
JavaScript
  • この例では、categories配列の中にネストされたitems配列をループ処理しています。
  • ネストが深くなるほど、:keyの適切な設定が重要です。

v-forの使い方

  • 配列やオブジェクトを繰り返しレンダリング。
  • 例: <li v-for=”item in items” :key=”item.id”>{{ item.name }}</li>。

キー属性 (:key) の重要性

  • 一意のキーを設定することで、リストの効率的な再レンダリングが可能。

ネストされたリスト

  • リスト内にさらにリストを表示する際もv-forを利用可能。

テンプレート式の応用

Vue.jsではテンプレート内でJavaScript式を使えますが、いくつかの制約があります。

JavaScript式の制限

  • テンプレート式では基本的なJavaScript操作が可能です。
<p>{{ message.toUpperCase() }}</p>
JavaScript

ただし、以下は禁止されています。

  • 複数行のコード
  • 宣言や代入(例: let=

複雑なテンプレート式を避けるためのベストプラクティス

  • コンポーネント内メソッドを活用: 複雑なロジックはテンプレート内ではなく、Vueインスタンスのメソッドで処理します。
<p>{{ formatMessage(message) }}</p>
HTML
const app = Vue.createApp({
  data() {
    return {
      message: 'こんにちは、Vue.js!'
    };
  },
  methods: {
    formatMessage(msg) {
      return msg.toUpperCase();
    }
  }
});
app.mount('#app');
JavaScript

算出プロパティの利用: ロジックを算出プロパティに移動すると、テンプレートが簡潔になります。

<p>{{ formattedMessage }}</p>
HTML
const app = Vue.createApp({
  data() {
    return {
      message: 'こんにちは、Vue.js!'
    };
  },
  computed: {
    formattedMessage() {
      return this.message.toUpperCase();
    }
  }
});
app.mount('#app');
JavaScript

まとめと実践例

実践例: 商品リストの表示

以下は、リストレンダリングやテンプレート式を組み合わせたサンプルです。

<div id="app">
  <h1>商品リスト</h1>
  <ul>
    <li v-for="product in filteredProducts" :key="product.id">
      {{ product.name }} - {{ product.price }}円
    </li>
  </ul>
</div>
HTML

ポイント

  1. id=”app”
    • Vue.jsアプリケーションがマウントされる対象のHTML要素を指定しています。
  2. v-for=”product in filteredProducts”
    • v-forは、filteredProducts(計算された商品のリスト)をループし、各商品をテンプレート内でレンダリングします。
    • productは、filteredProducts配列の現在のアイテムを指します。
  3. :key=”product.id”
    • ループ内の各要素に一意のキーを割り当て、効率的な再レンダリングをサポートします。product.idをキーとして使用。
  4. {{ product.name }} – {{ product.price }}円
    • product.nameとproduct.priceをMustache記法({{ }})でテンプレートに埋め込んでいます。
    • 例: 「商品A – 1000円」
const app = Vue.createApp({
  data() {
    return {
      products: [
        { id: 1, name: '商品A', price: 1000 },
        { id: 2, name: '商品B', price: 2000 },
        { id: 3, name: '商品C', price: 1500 }
      ],
      maxPrice: 1800
    };
  },
  computed: {
    filteredProducts() {
      return this.products.filter(product => product.price <= this.maxPrice);
    }
  }
});
app.mount('#app');
JavaScript

ポイント

  1. data()
    • products: 商品リストを表す配列。各商品はid, name, priceを持つオブジェクトです。
    • maxPrice: 商品の最大価格フィルタの基準値。
  2. computed
    • computedプロパティを使うと、リアクティブに計算された値を定義できます。
    • filteredProducts:
      • 商品リストproductsを基に、priceがmaxPrice以下の商品のみを抽出します。
      • filter()メソッドを使用して、配列を条件でフィルタリング。
      • 条件: product.price <= this.maxPrice
        • 各商品の価格がmaxPrice以下の場合にtrueを返し、結果の配列に含まれる。
  3. app.mount(‘#app’)
    • Vue.jsアプリケーションをHTMLのid=”app”要素にマウントし、テンプレートとデータを紐づけます。

動作の流れ

  1. 初期状態
    • maxPrice = 1800なので、productsから以下の商品がフィルタリングされます。
      • 商品A(1000円)
      • 商品C(1500円)
    • これにより、リストには「商品A – 1000円」と「商品C – 1500円」が表示されます。
  2. maxPriceの変更
    • Vue.jsのリアクティブ性により、maxPriceを更新すると自動でfilteredProductsが再計算され、リストが更新されます。
    • 例えば、maxPrice = 1200に変更すると、「商品A – 1000円」のみが表示されます。

よくある間違い

v-forでkeyを設定しない

  • ミス: リストレンダリング時に:keyを設定しない。
  • 対策: 必ず一意のキー(例: ID)を設定する。
<ul>
  <!-- ❌ 誤り: key属性が指定されていない -->
  <li v-for="item in items">{{ item.name }}</li>

  <!-- ✅ 正しいコード: key属性を設定 -->
  <li v-for="item in items" :key="item.id">{{ item.name }}</li>
</ul>
HTML

イベント修飾子を忘れる

  • ミス: フォーム送信時にページがリロードされる。
  • 対策: @submit.preventを使ってデフォルト動作を防ぐ。
<form>
  <!-- ❌ 誤り: prevent修飾子がないため、フォーム送信でページがリロードされる -->
  <button @submit="handleSubmit">送信</button>

  <!-- ✅ 正しいコード: prevent修飾子を使ってデフォルト動作を防ぐ -->
  <button @submit.prevent="handleSubmit">送信</button>
</form>
HTML

複雑なテンプレート式

  • ミス: テンプレートに長いJavaScript式を書く。
<div>
  <!-- ❌ 誤り: テンプレート内で複雑な式を記述 -->
  <p>{{ items.filter(item => item.price > 1000).map(item => item.name).join(', ') }}</p>

  <!-- ✅ 正しいコード: 算出プロパティを使用して簡潔に -->
  <p>{{ expensiveItemNames }}</p>
</div>

<script>
  const app = Vue.createApp({
    data() {
      return {
        items: [
          { id: 1, name: '商品A', price: 500 },
          { id: 2, name: '商品B', price: 1500 }
        ]
      };
    },
    computed: {
      expensiveItemNames() {
        return this.items.filter(item => item.price > 1000).map(item => item.name).join(', ');
      }
    }
  });
</script>
HTML

v-ifとv-forを同時に使う

  • ミス: 同じ要素にv-ifとv-forを設定。htmlコピーする編集する
<ul>
  <!-- ❌ 誤り: v-ifとv-forを同時に使う -->
  <li v-for="item in items" v-if="item.visible">{{ item.name }}</li>

  <!-- ✅ 正しいコード: 算出プロパティで条件付きリストを用意 -->
  <li v-for="item in visibleItems" :key="item.id">{{ item.name }}</li>
</ul>

<script>
  const app = Vue.createApp({
    data() {
      return {
        items: [
          { id: 1, name: '商品A', visible: true },
          { id: 2, name: '商品B', visible: false }
        ]
      };
    },
    computed: {
      visibleItems() {
        return this.items.filter(item => item.visible);
      }
    }
  });
</script>
HTML

Vue.jsのテンプレート構文は、データバインディングやイベントハンドリング、条件付きレンダリングなど、多彩な機能を提供することで、直感的で効率的なフロントエンド開発を実現します。この記事で解説した基本構文や応用テクニックを活用することで、Vue.jsの強力な機能を最大限に引き出すことができるでしょう。

初めての学習では、{{ }}やv-bindなどの基本的な構文から始め、次第にv-forや条件付きレンダリング、テンプレート式の応用といった高度な機能へ進むことが重要です。また、複雑なテンプレート式を避けるベストプラクティスを意識することで、コードの可読性と保守性も向上します。

Vue.jsは柔軟性と拡張性に優れたフレームワークです。基本を確実に押さえつつ、自分のプロジェクトに適した方法でこれらの機能を組み合わせることで、より高度で魅力的なアプリケーションを構築できるはずです。これを機に、Vue.jsの魅力的な世界をさらに深く探求してみてください!

コメント