Vue.jsの基本構文からコンポーネントの使い方まで解説

その他
  1. はじめに
  2. Vue インスタンスとは?
    1. Vue インスタンスの基本構造
    2. Vue インスタンスの要素
      1. createApp() でインスタンスを作成
      2. setup() でデータを管理
      3. テンプレートとの連携
    3. データバインディングの基本
      1. {{ }} を使ったデータの表示
      2. ポイント
    4. データの変更とリアクティブな動作
      1. ポイント
    5. 属性の動的変更 (v-bind)
      1. ポイント
  3. Vue.js のディレクティブ
    1. ディレクティブの概要
    2. 条件分岐 (v-if, v-else, v-show)
      1. v-if / v-else の基本
      2. v-if vs v-show の違い
    3. リストのレンダリング (v-for)
      1. ポイント
    4. フォーム要素のバインディング (v-model)
    5. イベントリスナー (v-on, @click)
  4. Vue におけるデータ操作の基本
    1. メソッド (methods) の使い方
      1. メソッドの特徴
    2. 算出プロパティ (computed) の活用
      1. メソッドとの違い
    3. ウォッチャー (watch) を使ったデータの監視
  5. Vue.jsにおけるコンポーネント
    1. Vue.js におけるコンポーネントの概念
    2. コンポーネント指向の開発のメリット
    3. コンポーネントの作成方法
      1. グローバルコンポーネントの作成
      2. シングルファイルコンポーネント(.vue ファイル)の作成
    4. 親コンポーネントと子コンポーネントの関係
      1. コンポーネントの入れ子構造
    5. props を使ったデータの受け渡し
      1. props とは?
      2. props のポイント
    6. props の型指定とデフォルト値
    7. props を利用する際の注意点
      1. 単方向データフローとは?
        1. ダメな例
      2. 正しい方法(emit を使う)
        1. 子コンポーネント
        2. ポイント
      3. 親コンポーネント
        1. 親コンポーネントの役割
        2. 動作の流れ
    8. $refs を使って子コンポーネントを操作
      1. 子コンポーネント (ChildComponent.vue)
      2. 親コンポーネント (App.vue)
    9. <slot> を使って柔軟なコンポーネントを作る
      1. 子コンポーネント (Card.vue)
      2. 親コンポーネント (App.vue)
    10. 名前付きスロット (<slot name="header">)
    11. スコープ付きスロット
  6. まとめ
    1. Vueの基本構文
    2. ディレクティブ
    3. データ操作
    4. コンポーネント

はじめに

この記事では、Vue.js(Vue 3)におけるVueインスタンス、データ操作、コンポーネントの利用方法まで解説します。

環境構築は下記記事に記載しているので参考にしてください。

Vue.js入門:特徴から環境構築まで完全ガイド
Vue.jsの基本から環境構築まで初心者向けにわかりやすく解説!CDN版とVue CLIの違い、セットアップ方法、便利なツールも紹介します。

Vue インスタンスとは?

Vue.js の基本単位となるのが「Vue インスタンス」です。Vue インスタンスは、

  • データの管理
  • イベントの処理
  • テンプレートとの連携 を担当し、Vue.js のアプリケーションを動作させる中心的な役割を果たします。

Vue インスタンスの基本構造

Vue 3 では、Vue インスタンスは createApp() を使って作成します。

App.vue の基本構造(Vue 3 の書き方)

<script setup>
import { ref } from "vue";

// Vue インスタンスが管理するデータ
const message = ref("こんにちは、Vue.js!");
</script>

<template>
  <div id="app">
    <!-- テンプレートで data の message を表示 -->
    <p>{{ message }}</p>
  </div>
</template>

Vue インスタンスの要素

createApp() でインスタンスを作成

main.js

import { createApp } from "vue";
import App from "./App.vue";

// Vue インスタンスを作成し、#app に適用
createApp(App).mount("#app");

setup() でデータを管理

Vue 3 では setup() 内で ref() を使用してリアクティブなデータを作成します。

Vue 3 の ref()

<script setup>
  import { ref } from "vue";
  
  const message = ref("こんにちは、Vue.js!");
<script>
  • ref() を使うと、リアクティブなデータを管理できます。

テンプレートとの連携

Vue 3 ではテンプレート内で {{ message }} を使ってデータを表示できます。

Vue 3 のテンプレート

<template>
  <div id="app">
    <p>{{ message }}</p>
  </div>
</template>

データバインディングの基本

Vue.js では、データバインディングを使ってデータを表示できます。

{{ }} を使ったデータの表示

Vue では マスタッシュ構文 {{ }} を使うことで、JavaScript の変数を HTML 内に埋め込むことができます。

テンプレートの例

<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script setup>
import { ref } from "vue";

// データをリアクティブに管理
const message = ref("Vue.js のデータバインディング!");
</script>

ポイント

  • {{ message }}Vue のデータ (message) を HTML に表示 します。
  • ref() を使うことで、データがリアクティブに更新されます。

データの変更とリアクティブな動作

Vue.js のデータを変更すると、UI に リアルタイムで反映 されます。

データの変更

<template>
  <div>
    <p>{{ message }}</p>
    <button @click="message = '変更されました!'">変更</button>
  </div>
</template>

<script setup>
import { ref } from "vue";

const message = ref("Vue.js のデータバインディング!");
</script>

ポイント

  • @click="message = '変更されました!'" により、ボタンをクリックすると message の値が変更され、画面も自動的に更新されます。

属性の動的変更 (v-bind)

Vue では v-bind を使って、HTML の属性を 動的に変更 できます。

画像の src を動的に変更

<template>
  <div>
    <img :src="imageSrc" alt="サンプル画像">
  </div>
</template>

<script setup>
import { ref } from "vue";

const imageSrc = ref("https://example.com/sample.jpg");
</script>

ポイント

  • v-bind:src="imageSrc":src="imageSrc" に省略できます。
  • imageSrc の値を変更すると、表示される画像も自動的に更新されます。

Vue.js のディレクティブ

ディレクティブの概要

Vue.js では、ディレクティブ(v- で始まる特別な属性) を使うことで、HTML 要素に対して 動的な振る舞い を設定できます。

例えば、v-if を使えば 条件によって要素の表示/非表示 を切り替えたり、v-for を使えば リストを自動生成 したりできます。

基本の形

<p v-if="isVisible">このメッセージは isVisible が true のとき表示されます。</p>
  • v-if="条件" の条件が true なら要素が表示、false なら削除されます。

条件分岐 (v-if, v-else, v-show)

v-if / v-else の基本

v-if を使うと、条件によって HTML の要素を追加/削除 できます。

ボタンをクリックしてメッセージを表示/非表示

<template>
  <div>
    <button @click="showMessage = !showMessage">切り替え</button>
    <p v-if="showMessage">こんにちは!</p>
    <p v-else>さようなら!</p>
  </div>
</template>

<script setup>
import { ref } from "vue";

const showMessage = ref(true);
</script>

v-if vs v-show の違い

ディレクティブ動作使い分け
v-if条件が false のとき DOM から削除頻繁に切り替えない場合に向いている
v-show条件が false のとき CSS(display: none)で非表示頻繁に表示を切り替える場合に向いている

v-show の例

<p v-show="showMessage">このメッセージは v-show を使っています。</p>

v-showCSS の display: none; で非表示 にするだけなので、v-if よりパフォーマンスに優れています。

リストのレンダリング (v-for)

リストを描画するときは v-for を使います。

配列データをリストとして表示

<template>
  <div>
    <ul>
      <li v-for="(item, index) in items" :key="index">
        {{ index + 1 }}: {{ item }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref } from "vue";

const items = ref(["りんご", "バナナ", "ぶどう"]);
</script>

ポイント

  • v-for="(item, index) in items"リストをループ処理
  • :key="index" を指定することで、Vue が各要素を正しく識別できる

フォーム要素のバインディング (v-model)

v-model を使うと、フォームの入力値とデータを リアルタイムで同期 できます。

テキスト入力フォーム

<template>
  <div>
    <input v-model="name" placeholder="名前を入力">
    <p>こんにちは、{{ name }} さん!</p>
  </div>
</template>

<script setup>
import { ref } from "vue";

const name = ref("");
</script>

入力した名前がリアルタイムで表示されます!

チェックボックス・ラジオボタン・セレクトボックスの例

<template>
  <div>
    <label>
      <input type="checkbox" v-model="checked"> チェックする
    </label>
    <p>チェック状態: {{ checked }}</p>

    <label>
      <input type="radio" v-model="gender" value="male"> 男性
    </label>
    <label>
      <input type="radio" v-model="gender" value="female"> 女性
    </label>
    <p>選択した性別: {{ gender }}</p>

    <select v-model="fruit">
      <option value="apple">りんご</option>
      <option value="banana">バナナ</option>
      <option value="grape">ぶどう</option>
    </select>
    <p>選択した果物: {{ fruit }}</p>
  </div>
</template>

<script setup>
import { ref } from "vue";

const checked = ref(false);
const gender = ref("");
const fruit = ref("apple");
</script>

イベントリスナー (v-on, @click)

Vue では v-on を使って イベント(クリックなど)を処理 できます。

@click を使ったボタンイベント

<template>
  <div>
    <button @click="count++">クリック回数: {{ count }}</button>
  </div>
</template>

<script setup>
import { ref } from "vue";

const count = ref(0);
</script>
  • @click="count++" でクリックすると count を増やす
  • v-on:click の代わりに @click を使うのが一般的

関数を使ったイベント処理

<template>
  <div>
    <button @click="increment">増やす</button>
    <p>カウント: {{ count }}</p>
  </div>
</template>

<script setup>
import { ref } from "vue";

const count = ref(0);

const increment = () => {
  count.value++;
};
</script>

methods の代わりに setup 内で関数を定義し、@click="increment" で呼び出します。

Vue におけるデータ操作の基本

Vue では、以下の 3 つの方法でデータを操作できます。

機能特徴使う場面
メソッド (methods)アクションを実行する関数ボタンをクリックしたとき などに実行
算出プロパティ (computed)キャッシュ された計算結果リアルタイムで計算が必要なとき
ウォッチャー (watch)データの変化を監視 し処理を実行API との連携やデータの監視

メソッド (methods) の使い方

methods を使うと、ボタンをクリックしたとき などのイベントで処理を実行できます。

📌 ボタンをクリックすると、カウントが増える例

<template>
  <div>
    <p>カウント: {{ count }}</p>
    <button @click="increment">増やす</button>
  </div>
</template>

<script setup>
import { ref } from "vue";

// カウントのデータ
const count = ref(0);

// メソッドの定義
const increment = () => {
  count.value++;
};
</script>

メソッドの特徴

  • 呼ばれるたびに実行 される(毎回計算し直す)
  • イベント (@click) によって処理を実行 するときに適している

引数を使ってデータを操作

<template>
  <div>
    <p>カウント: {{ count }}</p>
    <button @click="increment(2)">+2</button>
    <button @click="increment(5)">+5</button>
  </div>
</template>

<script setup>
import { ref } from "vue";

const count = ref(0);

// メソッドに引数を渡す
const increment = (value) => {
  count.value += value;
};
</script>
  • increment(2) のように引数を渡して処理を変更できます。

算出プロパティ (computed) の活用

computedリアクティブなデータを基に自動的に計算 し、その結果をキャッシュする機能です。

文字数を自動計算する例

<template>
  <div>
    <input v-model="message" placeholder="入力してください">
    <p>文字数: {{ charCount }}</p>
  </div>
</template>

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

const message = ref("");

// 算出プロパティ(computed)
const charCount = computed(() => {
  return message.value.length;
});
</script>
  • charCountmessage が変わると自動で計算される
  • キャッシュされるため、message に変更がない場合は再計算されない

メソッドとの違い

methodscomputed
実行のタイミング呼ばれるたびに再計算データが変わったときのみ再計算(キャッシュあり)
使う場面イベントをトリガーに処理する計算結果をキャッシュしたい

メソッドを使うと、毎回計算される

const charCount = () => {
  return message.value.length;
};

computed を使った方が効率的!

ウォッチャー (watch) を使ったデータの監視

watch を使うと、データの変化を リアルタイムで監視 し、何らかの処理を実行できます。

テキストを入力すると、コンソールにログを出す

<template>
  <div>
    <input v-model="message" placeholder="入力してください">
    <p>入力内容: {{ message }}</p>
  </div>
</template>

<script setup>
import { ref, watch } from "vue";

const message = ref("");

// watch でデータの変化を監視
watch(message, (newValue, oldValue) => {
  console.log(`変更前: ${oldValue}, 変更後: ${newValue}`);
});
</script>
  • message が変わるたびに 新しい値と古い値を取得 して処理できる

検索フォームで API 連携

<template>
  <div>
    <input v-model="query" placeholder="検索ワードを入力">
    <p>検索結果: {{ result }}</p>
  </div>
</template>

<script setup>
import { ref, watch } from "vue";

const query = ref("");
const result = ref("");

// データの変更を監視
watch(query, async (newQuery) => {
  if (newQuery.length > 2) {
    result.value = `「${newQuery}」の検索結果`;
  } else {
    result.value = "";
  }
});
</script>
  • query の値が変わるたびに API を呼び出す(今回は簡単なデモ)

Vue.jsにおけるコンポーネント

Vue.js におけるコンポーネントの概念

コンポーネントとは、「再利用可能な UI の部品」 です。
例えば、ボタンやカード、フォームなどを 独立したパーツ にすることで、使い回しや管理がしやすくなります。

コンポーネント指向の開発のメリット

メリット説明
再利用性同じコンポーネントを複数のページや箇所で使える
保守性の向上各コンポーネントが独立しているため、修正が簡単
可読性の向上コードが整理され、分かりやすくなる

例えば、「ボタン」をコンポーネント化すると…

<template>
  <button class="my-button">クリック</button>
</template>

<style>
.my-button {
  background-color: blue;
  color: white;
  padding: 10px;
}
</style>

こうすることで、「ボタンを使いたい場所にコンポーネントを呼び出すだけで使える」 ようになります!

コンポーネントの作成方法

グローバルコンポーネントの作成

Vue 3 では、app.component() を使ってグローバルコンポーネントを登録できます。

ボタンのコンポーネントを作成

<template>
  <div id="app">
    <my-button></my-button>
  </div>
</template>

<script>
import { createApp } from "vue";

const app = createApp({
  template: "<my-button></my-button>",
});

// コンポーネントを登録
app.component("my-button", {
  template: `<button>クリック</button>`,
});

app.mount("#app");
</script>

シングルファイルコンポーネント(.vue ファイル)の作成

Vue では、.vue ファイルを使って コンポーネントを分割 できます。

ファイル構成

src/
 ├── components/
 │   ├── MyButton.vue
 ├── App.vue
 ├── main.js

MyButton.vue(ボタンコンポーネント)

<template>
  <button>クリック</button>
</template>

App.vue(親コンポーネント)

<template>
  <div>
    <MyButton />
  </div>
</template>

<script setup>
import MyButton from "./components/MyButton.vue";
</script>
  • import MyButton from "./components/MyButton.vue"; でコンポーネントを読み込む
  • <MyButton /> でコンポーネントを表示する

親コンポーネントと子コンポーネントの関係

コンポーネントの入れ子構造

Vue のコンポーネントは 親子関係 を作ることができます。

親コンポーネントが子コンポーネントを呼び出す

<template>
  <div>
    <ChildComponent />
  </div>
</template>

<script setup>
import ChildComponent from "./ChildComponent.vue";
</script>

このように、親コンポーネントの中に子コンポーネントを組み込む ことで、アプリを部品ごとに分割できます。

props を使ったデータの受け渡し

props とは?

props親コンポーネントから子コンポーネントへデータを渡す ための仕組みです。

親コンポーネント (App.vue)

<template>
  <div>
    <MessageDisplay message="こんにちは!" />
  </div>
</template>

<script setup>
import MessageDisplay from "./components/MessageDisplay.vue";
</script>

子コンポーネント (MessageDisplay.vue)

<template>
  <p>{{ message }}</p>
</template>

<script setup>
import { defineProps } from "vue";

// 親コンポーネントから受け取る props を定義
defineProps({
  message: String,
});
</script>

props のポイント

  • defineProps({ message: String }) で受け取るデータを定義
  • 親コンポーネントで message="こんにちは!" を指定すると、子コンポーネントで {{ message }} として表示される

props の型指定とデフォルト値

Vue 3 では、props型指定デフォルト値の設定 ができます。

型指定とデフォルト値を設定

<script setup>
import { defineProps } from "vue";

defineProps({
  message: {
    type: String,
    default: "デフォルトのメッセージ",
  },
});
</script>
  • type: Stringmessage は文字列として受け取る
  • default: "デフォルトのメッセージ"message が渡されなかった場合のデフォルト値を設定

props を利用する際の注意点

Vue の props単方向データフロー になっています。

単方向データフローとは?

Vue の props は親コンポーネントから子コンポーネントへ 一方向(単方向) にデータを渡す仕組みです。
つまり、子コンポーネント内で props の値を直接変更することはできません

ダメな例
<script setup>
defineProps(["message"]);

// NG: props の値を直接変更しようとするとエラー
message = "変更したい";
</script>

なぜダメなのか?

  • Vue では props は「読み取り専用」として扱われる。
  • props を直接変更すると、Vue の リアクティブシステム に混乱を引き起こし、エラーが発生する可能性がある。

正しい方法(emit を使う)

emit を使って、親コンポーネントにデータの変更を通知します。

子コンポーネント
<template>
  <input v-model="newMessage" />
  <button @click="updateMessage">変更</button>
</template>

<script setup>
import { defineProps, defineEmits, ref } from "vue";

const props = defineProps(["message"]); // 親から受け取る
const emit = defineEmits(["update"]);   // 親へイベントを送る準備
const newMessage = ref(props.message);  // ローカルのリアクティブデータとしてコピー

const updateMessage = () => {
  emit("update", newMessage.value); // 親に新しいメッセージを送信
};
</script>
ポイント
  1. props.message をそのまま変更せずに newMessage という ローカルなリアクティブデータ を作成。
  2. v-model を使って input に双方向バインディング。
  3. button クリック時に updateMessage を実行し、emit("update", newMessage.value) で親コンポーネントに新しい値を送る。

親コンポーネント

親コンポーネントでは、子から受け取った update イベントを処理し、データを更新します。

<template>
  <ChildComponent :message="message" @update="handleUpdate" />
  <p>現在のメッセージ: {{ message }}</p>
</template>

<script setup>
import { ref } from "vue";
import ChildComponent from "./ChildComponent.vue"; // 子コンポーネントをインポート

const message = ref("初期メッセージ");

const handleUpdate = (newMessage) => {
  message.value = newMessage; // 子から受け取った値で更新
};
</script>
親コンポーネントの役割
  1. messageref で定義し、ChildComponentprops として渡す。
  2. @update="handleUpdate" を指定し、子コンポーネントからのイベントを受け取る。
  3. handleUpdate メソッドで message を更新し、変更を適用。
動作の流れ
  1. 親が messageprops として子へ渡す
  2. 子が props.messagenewMessage にコピー
  3. 子で input を編集し、updateMessage をクリック
  4. emit("update", newMessage.value) で親へ通知
  5. 親が handleUpdatemessage を更新
  6. 親の message が変わると、子の props.message も更新される

$refs を使って子コンポーネントを操作

通常は propsemit を使ってデータのやり取りを行いますが、
$refs を使うと 親コンポーネントから子コンポーネントのメソッドやデータに直接アクセス できます。

$refs を使うと、子コンポーネントのメソッドを親コンポーネントから実行 できます。

子コンポーネント (ChildComponent.vue)

<template>
  <p>現在のカウント: {{ count }}</p>
</template>

<script setup>
import { ref } from "vue";

const count = ref(0);

// カウントを増やすメソッド
const increment = () => {
  count.value++;
};

// メソッドを外部からアクセス可能にする
defineExpose({ increment });
</script>
  • defineExpose({ increment }) を使うと、親コンポーネントから increment() にアクセスできる

親コンポーネント (App.vue)

<template>
  <div>
    <ChildComponent ref="child" />
    <button @click="increaseChildCount">子のカウントを増やす</button>
  </div>
</template>

<script setup>
import { ref } from "vue";
import ChildComponent from "./ChildComponent.vue";

const child = ref(null);

// 子コンポーネントのメソッドを実行
const increaseChildCount = () => {
  child.value.increment();
};
</script>
  • <ChildComponent ref="child" />子コンポーネントにアクセス
  • child.value.increment();子のメソッドを実行

親から子のデータやメソッドを操作できるが、できるだけ propsemit を使うのが推奨

<slot> を使って柔軟なコンポーネントを作る

<slot> を使うと、親コンポーネントから子コンポーネントの中に自由な内容を挿入 できます。

通常、子コンポーネントの内容は固定ですが、<slot> を使うと柔軟にコンテンツを挿入 できます。

子コンポーネント (Card.vue)

<template>
  <div class="card">
    <slot></slot>
  </div>
</template>

<style>
.card {
  border: 1px solid gray;
  padding: 20px;
  margin: 10px;
}
</style>
  • <slot></slot> の部分に、親から挿入するコンテンツが入る

親コンポーネント (App.vue)

<template>
  <Card>
    <h2>タイトル</h2>
    <p>スロットを使った動的な内容</p>
  </Card>
</template>

<script setup>
import Card from "./Card.vue";
</script>
  • <Card> の中に h2p を自由に入れられる!

これでコンポーネントの内容を柔軟に変更できる!

名前付きスロット (<slot name="header">)

スロットを複数に分けて、異なる箇所にコンテンツを挿入 できます。

Card.vue(子コンポーネント)

<template>
  <div class="card">
    <header><slot name="header"></slot></header>
    <main><slot></slot></main>
  </div>
</template>

App.vue(親コンポーネント)

<template>
  <Card>
    <template #header>
      <h2>カードのタイトル</h2>
    </template>
    <p>本文の内容</p>
  </Card>
</template>
  • #header を指定すると、<slot name="header"> の部分に挿入される

レイアウトを統一しつつ、コンテンツを柔軟に変更できる!

スコープ付きスロット

子コンポーネントのデータを親に渡し、スロット内で利用できます。

List.vue(子コンポーネント)

<template>
  <ul>
    <slot v-for="item in items" :item="item"></slot>
  </ul>
</template>

<script setup>
defineProps(["items"]);
</script>

App.vue(親コンポーネント)

<template>
  <List :items="['りんご', 'バナナ', 'ぶどう']">
    <template #default="{ item }">
      <li>{{ item }}</li>
    </template>
  </List>
</template>
  • #default="{ item }" → 子の items を取得して表示!

まとめ

Vueの基本構文

機能説明使用例
{{ message }}データをテンプレートに表示<p>{{ message }}</p>
@click="message = '変更'"データを変更し、UI を更新<button @click="message = '変更'">
v-bind:src="imageSrc"画像や属性を動的に変更<img :src="imageSrc">
:class="{ active: isActive }"クラスの適用を動的に制御<p :class="{ active: isActive }">
:style="{ color: textColor }"スタイルを動的に変更<p :style="{ color: textColor }">

ディレクティブ

ディレクティブ説明
v-if / v-else条件によって要素を追加・削除<p v-if="isVisible">表示</p>
v-showCSS の display: none; で非表示<p v-show="isVisible">表示</p>
v-for配列のデータをリスト表示<li v-for="item in items">{{ item }}</li>
v-modelフォーム入力とデータを同期<input v-model="name">
v-on / @clickクリックなどのイベント処理<button @click="doSomething">

データ操作

機能説明使う場面
methodsイベントで関数を実行ボタンクリックで処理を実行
computedキャッシュされた計算結果を返すリアルタイム計算(文字数など)
watchデータの変化を監視し処理を実行API 連携・データの変更を検知
  • methodsイベント発生時に実行
  • computedデータをキャッシュして効率的に計算
  • watchデータの変更を監視して処理を実行

コンポーネント

項目説明
コンポーネントとは?Vue で UI を分割し、再利用可能な部品を作る仕組み
コンポーネントの作成.vue ファイルで作成し、import して使う
親子コンポーネントの関係親が子を呼び出し、props でデータを渡す
props親→子のデータ受け渡し(型指定・デフォルト値設定可能)
単方向データフローprops は親からしか変更できない
emit子→親へデータを渡す
$refs親→子のメソッドやデータを直接操作
<slot>柔軟なコンテンツの挿入
名前付きスロット#header など特定の箇所に挿入
スコープ付きスロット子のデータを親に渡す

コメント

タイトルとURLをコピーしました