はい、承知いたしました。Vue.jsについて、初心者向けに特徴と基本を約5000語で詳細に解説する記事を作成します。
【初心者向け】Vue.jsとは?特徴と基本をわかりやすく解説
はじめに:現代Web開発とVue.js
WebサイトやWebアプリケーションは、私たちの生活に欠かせないものとなりました。単に情報を表示するだけでなく、ユーザーとのインタラクションが豊富で、動的にコンテンツが変化するような高度なアプリケーションが求められています。
かつて、Webページに動きをつけるためには、JavaScriptを直接書いてDOM(Document Object Model)と呼ばれるHTML要素の構造を操作する必要がありました。しかし、アプリケーションの規模が大きくなるにつれて、この方法は非常に複雑になり、コードの管理や保守が困難になるという問題がありました。
このような背景から生まれたのが、「フロントエンドフレームワーク」や「ライブラリ」と呼ばれるものです。これらは、Webアプリケーションのユーザーインターフェース(UI)を効率的かつ構造的に構築するためのツールセットを提供します。代表的なものに、React、Angular、そして今回ご紹介するVue.jsがあります。
これらのフレームワークを使うことで、開発者はUIの構築に集中でき、データの変更に応じて自動的に画面が更新される仕組みや、複雑なUIを再利用可能な部品(コンポーネント)として管理する仕組みを利用できるようになります。これにより、開発効率が大幅に向上し、大規模なアプリケーションでも管理しやすいコードを書くことが可能になります。
この記事では、特に初心者の方に向けて、数あるフロントエンド技術の中でも人気が高く、学習しやすいと言われているVue.jsに焦点を当てて、その特徴や基本的な使い方を徹底的に解説します。Vue.jsがどのようなものか、なぜ多くの開発者に選ばれているのか、そして実際に手を動かして基本的なアプリケーションを作るにはどうすれば良いのかを、順を追って丁寧に説明していきます。
プログラミングやWeb開発は初めて、あるいはJavaScriptは少し触ったことがあるけれど、フレームワークは未知の世界という方も、この記事を最後まで読めば、Vue.jsの全体像を把握し、基本的なアプリケーションを作成できるようになることを目指します。さあ、Vue.jsの世界へ飛び込んでみましょう!
Vue.jsとは何か?
Vue.js(読み方:ビュー・ジェイエス)は、インタラクティブなユーザーインターフェースを構築するためのJavaScriptフレームワークです。2014年にEvan You氏によって開発され、現在はオープンソースプロジェクトとして世界中の多くの開発者によって支えられています。
Vue.jsは、ReactやAngularといった他の主要なフレームワークと比較して、以下のような特徴を持っています。
- プログレッシブフレームワークであること: これがVue.jsの最大の特徴の一つです。プログレッシブとは「段階的」という意味。Vue.jsは、プロジェクトの必要に応じて、小さな機能から導入することができます。既存のプロジェクトの一部にインタラクティブな要素を追加したい場合など、HTMLに数行のコードを追加するだけでVue.jsの機能を利用開始できます。もちろん、本格的なシングルページアプリケーション(SPA)を構築するための強力なツールも提供されています。この柔軟性のおかげで、学習コストが比較的低く、既存のプロジェクトにも導入しやすいとされています。
- 学習コストが比較的低い: シンプルで直感的なAPI(Application Programming Interface)と、分かりやすいドキュメントのおかげで、Web開発やJavaScriptの経験が浅い初心者でも比較的容易に学習を開始できます。HTML、CSS、JavaScriptの基本的な知識があれば、すぐにVue.jsのコードを書き始めることができるでしょう。
- 柔軟性: Vue.jsは、UI層(画面表示に関わる部分)に特化しています。ルーティング(画面遷移)や状態管理といった機能は、公式が提供するライブラリ(Vue RouterやPiniaなど)やサードパーティ製のライブラリと組み合わせて使用します。これにより、開発者はプロジェクトの要件に応じて最適なライブラリを選択できる柔軟性があります。
- パフォーマンス: Vue.jsは軽量で高速に動作するように設計されています。効率的な仮想DOM(後述)の実装や、細粒度のリアクティビティシステムにより、データの変更が素早く画面に反映されます。
これらの特徴から、Vue.jsは小規模なウィジェット開発から大規模なエンタープライズアプリケーションまで、幅広い用途で利用されています。特に、日本のWeb開発コミュニティでも人気が高く、多くの企業やプロジェクトで採用されています。
では、なぜVue.jsがこれほどまでに多くの開発者に選ばれているのでしょうか? その理由を探るために、Vue.jsの具体的な特徴をさらに深く掘り下げてみましょう。
Vue.jsの主な特徴をさらに詳しく
Vue.jsを理解する上で核となるいくつかの特徴があります。これらを理解することで、Vue.jsがどのようにWebアプリケーションを構築するのか、その哲学が見えてきます。
1. プログレッシブフレームワークであること (Progressive Framework)
先ほども触れましたが、この「プログレッシブ」という性質がVue.jsの大きな魅力です。これは、Vue.jsを「段階的に導入できる」という意味です。
- 最小限の導入: 既存のWebサイトに、特定の要素だけインタラクティブにしたい、といったケースを考えてみましょう。jQueryのようなライブラリを使う感覚で、CDN(Content Delivery Network)からVue.jsを読み込み、HTMLの一部に簡単なVue.jsのコードを書くだけでその機能を実現できます。ページ全体をVue.jsで作る必要はありません。
- スケーラビリティ: もっと複雑な、ページ遷移のないシングルページアプリケーション(SPA)を作りたい場合は、Vue CLIやViteといった公式のビルドツールを使ってプロジェクトを構築し、ルーティングを担当するVue Routerや、複雑な状態管理を行うPinia(Vuexの後継)といった公式ライブラリを組み合わせて使用します。これにより、大規模なアプリケーション開発にも対応できます。
このプログレッシブ性により、Vue.jsは様々な規模や種類のプロジェクトに適用可能です。初心者にとっては、小さな一歩から始められるという点で学習のハードルが低く感じられるでしょう。
2. コンポーネント指向 (Component-Oriented)
現代のフロントエンド開発において、コンポーネント指向は必須のアプローチとなっています。Vue.jsも強力なコンポーネントシステムを備えています。
- コンポーネントとは?: UIを構成する独立した、再利用可能な部品のことです。例えば、ウェブサイトのヘッダー、フッター、ナビゲーションメニュー、ボタン、カード型の記事表示ブロックなど、これらはすべてコンポーネントとして設計できます。
- メリット:
- 再利用性: 一度作成したコンポーネントは、アプリケーション内の様々な場所で、あるいは別のプロジェクトでも再利用できます。これにより、開発効率が向上します。
- 保守性: コンポーネントごとに独立しているため、特定の部品の改修が他の部分に与える影響を限定できます。問題が発生した場合も、原因を特定しやすくなります。
- 可読性: アプリケーション全体がコンポーネントの組み合わせとして表現されるため、コードの構造が分かりやすくなります。
- 開発の分業: チーム開発において、担当者ごとに異なるコンポーネントの開発を並行して進めることができます。
Vue.jsでは、「単一ファイルコンポーネント (Single File Component: SFC)」という.vue拡張子を持つファイル形式が一般的に使われます。このファイルの中に、そのコンポーネントに必要なHTML(<template>タグ)、JavaScript(<script>タグ)、CSS(<style>タグ)をまとめて記述します。これにより、コンポーネントごとに必要なコードがカプセル化され、管理しやすくなります。
“`html
“`
このように、1つのファイルでコンポーネントに必要な全てが完結しているのがSFCの特徴です。
3. データバインディング (Data Binding)
データバインディングは、アプリケーションのデータ(JavaScriptの変数など)と、ユーザーインターフェース(HTMLの表示など)を結びつける仕組みです。Vue.jsでは、データバインディングを使って、JavaScriptのデータをHTMLに表示したり、ユーザーの入力に応じてJavaScriptのデータを更新したりできます。
- 単方向データバインディング: JavaScriptのデータをHTMLに表示する際などに使われます。データが変更されると、自動的にHTMLの表示が更新されます。Vue.jsでは主に
{{ }}(Mustache構文)やv-bindディレクティブ(後述)を使って実現します。 - 双方向データバインディング: フォームの入力要素などでよく使われます。HTMLの入力フィールドでユーザーが値を変更すると、それと同時に対応するJavaScriptのデータも更新されます。逆に、JavaScriptのデータを変更すると、入力フィールドの値も更新されます。Vue.jsでは主に
v-modelディレクティブを使って実現します。
データバインディングの存在により、開発者はDOMを直接操作することなく、データの状態だけを意識してアプリケーションを構築できます。データの変更を検知し、DOMを更新する処理はVue.jsが自動的に行ってくれます。
4. リアクティブシステム (Reactivity System)
データバインディングを支えているのが、Vue.jsの強力なリアクティブシステムです。これは、JavaScriptのデータ(特にVueインスタンスやコンポーネントのdataオプションで定義されたデータ)の変更をVue.jsが検知し、その変更に依存する部分だけを効率的に更新する仕組みです。
例えば、messageというデータが画面に表示されているとします。JavaScriptでmessage = '新しいメッセージ';のように値を変更すると、Vue.jsのリアクティブシステムがそれを検知し、画面上のmessageが表示されている部分だけを自動的に書き換えます。
Vue.js(特にVue 3以降)では、JavaScriptのProxyオブジェクトを使ってこのリアクティビティを実現しています。データオブジェクトがProxyでラップされることで、プロパティへのアクセス(getter)や変更(setter)をVue.jsがフックできるようになります。
このリアクティブシステムがあるおかげで、開発者は「このデータが変わったら、あの画面を更新する」といった煩雑なDOM操作のコードを書く必要がなくなります。ただデータを変更すれば、画面は自動で最新の状態になります。
リアクティブシステムと関連して、Vue.jsには以下の便利な機能があります。
- 算出プロパティ (Computed Properties): 既存のリアクティブなデータに基づいて、新しいデータを生成したい場合に使います。算出プロパティは、依存するデータが変更されない限り結果をキャッシュするため、パフォーマンス面で有利です。例えば、
firstNameとlastNameというデータから、フルネームを生成するなどの場合に使用します。 - ウォッチャ (Watchers): 特定のリアクティブなデータの変更を「監視」し、データが変更されたときに非同期処理などの副作用を実行したい場合に使います。例えば、入力フィールドの値が変更されたときに、その値を使ってサーバーに検索リクエストを送るなどの場合に使用します。
算出プロパティは「結果を計算する」のに適しており、ウォッチャは「データの変更をトリガーに何か処理を行う」のに適しています。これらを使うことで、データの変化に応じた様々なロジックを簡潔に記述できます。
5. テンプレート構文 (Template Syntax)
Vue.jsは、HTMLベースのテンプレート構文を使用します。これは、開発者が使い慣れたHTMLの構文を拡張する形で、動的なデータを表示したり、条件によって要素を表示・非表示したり、リストをレンダリングしたりといった処理を記述できるものです。
Vue.jsのテンプレート構文の主な要素は以下の通りです。
-
テキスト補間 (Text Interpolation): 最も基本的なデータ表示方法です。二重波括弧
{{ }}を使って、JavaScriptのデータをHTMLのテキストとして表示します。html
<p>{{ message }}</p>messageというJavaScriptの変数の値がここに表示されます。 -
ディレクティブ (Directives):
v-という接頭辞を持つ特別な属性です。HTML要素にVue.jsの特定の振る舞いを適用するために使われます。例えば、v-ifは条件によって要素を表示・非表示、v-forはリストのレンダリング、v-onはイベントハンドリング、v-bindは属性のバインディングなどがあります。“`html
ログイン中です
- {{ item.name }}
これらのディレクティブを使うことで、HTMLの中にJavaScriptのロジックを埋め込むことができ、宣言的にUIを記述できます。
6. 仮想DOM (Virtual DOM)
Vue.jsはパフォーマンス最適化のために仮想DOMを採用しています。
- DOMとは?: ウェブブラウザがHTMLドキュメントを解析して構築する、メモリ上のツリー構造のことです。JavaScriptを使って画面の表示を変更する際には、このDOMを操作します。しかし、DOM操作は一般的にコストが高く、特に複雑なUIで頻繁にDOMを変更するとパフォーマンスが悪化しやすいという問題があります。
- 仮想DOMとは?: 仮想DOMは、実際のDOMの軽量なJavaScriptオブジェクト表現です。Vue.jsは、データの変更があった際に、直接DOMを操作するのではなく、まず仮想DOMツリーを更新します。そして、更新後の仮想DOMツリーと更新前の仮想DOMツリーを比較(差分検出 – “diffing”)し、変更があった最小限の部分だけを特定します。最後に、特定された差分のみを実際のDOMに反映(パッチ適用 – “patching”)します。
この仮想DOMによる効率的な更新処理のおかげで、アプリケーションのパフォーマンスが向上し、複雑なUIでもスムーズなユーザー体験を提供できます。開発者は仮想DOMの存在を意識する必要はほとんどなく、通常通りデータを変更すれば、Vue.jsが最適な更新処理を行ってくれます。
7. エコシステム (Ecosystem)
Vue.js本体はUI構築に特化していますが、本格的なアプリケーション開発に必要な様々な機能は、公式が提供する関連ライブラリやツール(「エコシステム」と呼ばれます)によって補完されています。
- Vue Router: シングルページアプリケーション(SPA)で、ブラウザのアドレスバーのURLと表示するコンポーネントを対応付け、ページ遷移を実現するためのライブラリです。
- Pinia (推奨) / Vuex: アプリケーション全体で共有される複雑な「状態」(データ)を一元管理するためのライブラリです。特に大規模なアプリケーションで、複数のコンポーネント間でデータをやり取りする必要がある場合に役立ちます。PiniaはVuexよりもシンプルで使いやすい設計になっています。
- Vite: 高速な開発サーバーとビルドツールです。モダンなJavaScript開発において、ソースコードをブラウザが理解できる形に変換したり、バンドル(複数のファイルを一つにまとめたり)したりする作業を効率的に行います。Vue CLIに代わる新しい公式の推奨ビルドツールです。
- Vue Devtools: ブラウザの拡張機能として提供される開発者ツールです。Vue.jsアプリケーションのコンポーネントツリーやデータの状態などを確認・デバッグする際に非常に役立ちます。
これらのエコシステムを活用することで、Vue.jsを使ってより本格的で機能豊富なアプリケーションを開発することが可能になります。プログレッシブな性質により、必要に応じてこれらのツールやライブラリを追加していくことができます。
Vue.jsを始める準備
さて、Vue.jsがどのようなものか、その特徴を理解したところで、実際にVue.jsを使った開発を始めるための準備を行いましょう。
Vue.jsを使った開発環境を構築する方法はいくつかありますが、モダンなアプリケーション開発においては、ビルドツールを使った方法が一般的です。ここでは、公式に推奨されているビルドツール「Vite(ヴィート)」を使った環境構築方法を中心に解説します。
必要なもの:
- Node.js: Vue.jsはJavaScriptの実行環境であるNode.js上で動作します。また、開発に必要なパッケージ管理(npm, yarn, pnpmなど)やビルドツールもNode.jsに依存します。公式ウェブサイトから最新のLTS(Long Term Support)版をダウンロードしてインストールしてください。(Node.jsのインストールにはnpmも含まれています)
- npm, yarn, または pnpm: Node.jsのパッケージマネージャーです。Vue.js本体やその他のライブラリをインストールするために使用します。Node.jsをインストールするとnpmが一緒にインストールされます。yarnやpnpmはnpmの代替として利用できますが、初心者の方はまずnpmを使えば十分です。
- テキストエディタ / IDE: コードを書くためのエディタが必要です。Vue.js開発には、Visual Studio Code (VS Code) が特におすすめです。多くの便利な拡張機能があり、Vue.jsのコード補完やシンタックスハイライトを強力にサポートしてくれます。
開発環境の構築 (Viteを使用):
Viteは非常に高速なビルドツールで、Vue.js開発において推奨されています。Viteを使ってVue.jsプロジェクトを新規作成する手順は以下の通りです。
-
ターミナルまたはコマンドプロンプトを開く:
Windowsの場合は「コマンドプロンプト」または「PowerShell」、macOSの場合は「ターミナル」を開きます。 -
プロジェクトを作成したいディレクトリに移動:
cdコマンドを使って、プロジェクトを作成したいフォルダに移動します。
bash
cd path/to/your/development/folder -
Viteを使ってVue.jsプロジェクトを作成:
以下のコマンドを実行します。my-vue-appの部分は、作成したいプロジェクトの名前(任意のフォルダ名)に変更してください。bash
npm create vue@latest my-vue-appこのコマンドを実行すると、Viteが対話形式でいくつかの設定を尋ねてきます。通常は以下のように選択・入力します(カッコ内は推奨または一般的な選択肢)。
Project name:(my-vue-app または任意の名前)Add TypeScript?(No / Yes – 初心者の方はまずNoで良いでしょう)Add JSX Support?(No – Vueでは通常使いません)Add Vue Router for Single Page Application development?(Yes – SPAを作るなら必須)Add Pinia for State Management?(Yes – 状態管理が必要なら)Add Vitest for Unit Testing?(No / Yes – テストは後からでも追加可能)Add an End-to-End Testing Solution?(No / Cypress / Playwright – E2Eテストも後から追加可能)Add ESLint for code linting?(Yes – コード規約チェック)Add Prettier for code formatting?(Yes – コード自動整形)
選択が終わると、Viteがプロジェクトの雛形を作成してくれます。
-
作成されたプロジェクトディレクトリに移動:
bash
cd my-vue-app -
必要なパッケージをインストール:
プロジェクトの実行に必要なライブラリ(Vue.js本体、Vue Router、Piniaなど、手順3で選択したもの)をインストールします。“`bash
npm installあるいは yarn install, pnpm install
“`
-
開発サーバーを起動:
これで開発の準備が整いました。以下のコマンドを実行すると、Viteが開発サーバーを起動し、ブラウザでアプリケーションを確認できるようになります。“`bash
npm run devあるいは yarn dev, pnpm dev
“`
ターミナルに表示されるURL(例:
http://localhost:5173/)をブラウザで開いてみてください。Vue.jsのWelocmeページが表示されれば成功です!
プロジェクト構造の簡単な解説:
Viteで作成されたプロジェクトの主要なファイルやフォルダの役割を簡単に見てみましょう。
my-vue-app/
├── node_modules/ # インストールされたライブラリが格納される
├── public/ # 静的ファイル(画像など)を置く場所。そのまま公開される
├── src/ # アプリケーションのソースコード本体
│ ├── assets/ # 画像やフォントなど(ビルド時に処理されるもの)
│ ├── components/ # コンポーネントを置く場所
│ ├── router/ # (Vue Routerを選択した場合) ルーティング設定
│ ├── stores/ # (Piniaを選択した場合) ストア(状態管理)
│ ├── App.vue # アプリケーションのルートコンポーネント
│ ├── main.js # アプリケーションのエントリーポイント(Vueアプリの起動処理)
│ └── style.css # グローバルなスタイルシート
├── .eslintrc.cjs # (ESLintを選択した場合) ESLintの設定ファイル
├── .gitignore # Gitで管理しないファイル・フォルダを指定
├── .prettierrc.cjs # (Prettierを選択した場合) Prettierの設定ファイル
├── index.html # アプリケーションのエントリーHTMLファイル(ビルド時にも使われる)
├── package.json # プロジェクトの情報、依存ライブラリ、スクリプトなどを管理
├── vite.config.js # Viteの設定ファイル
└── README.md # プロジェクトの説明
開発のメインとなるのはsrcフォルダの中身です。特にmain.jsがアプリケーションの開始点、App.vueが一番親となるコンポーネント、componentsフォルダに作成するコンポーネントを置いていくことになります。
これで、Vue.jsを使った開発を始めるための準備が整いました。次に、具体的なコードを書きながら、Vue.jsの基本的な使い方を見ていきましょう。
Vue.jsの基本的な使い方
開発環境が構築できたので、実際にコードを書いてVue.jsの基本的な機能を体験してみましょう。まずは一番シンプルな例から始め、Vueインスタンスの作成、データの表示、イベントの処理といった基本を学んでいきます。
Viteで作成したプロジェクトのsrc/main.jsファイルとsrc/App.vueファイルを編集していきます。
1. Vueアプリケーションの作成とマウント
src/main.jsは、Vueアプリケーション全体の設定を行い、HTMLの特定の要素にマウント(関連付け)して表示する役割を担います。
デフォルトのmain.jsは以下のようになっているはずです(ViteでVue RouterやPiniaを選択した場合は、それらの設定も含まれます)。
“`javascript
// src/main.js
import { createApp } from ‘vue’
import App from ‘./App.vue’
import ‘./style.css’
// Vueアプリケーションを作成
const app = createApp(App)
// Vue Routerを使用する場合
// import router from ‘./router’
// app.use(router)
// Piniaを使用する場合
// import { createPinia } from ‘pinia’
// app.use(createPinia())
// アプリケーションをHTMLの特定の要素にマウント(表示)
app.mount(‘#app’)
“`
import { createApp } from 'vue': Vue 3から導入された関数で、Vueアプリケーションの新しいインスタンスを作成するために使用します。import App from './App.vue': アプリケーションのルートとなるコンポーネント(通常はApp.vue)をインポートします。const app = createApp(App):createApp関数にルートコンポーネントを渡して、Vueアプリケーションのインスタンスを作成します。このappインスタンスに対して、ルーティング (.use(router)) や状態管理 (.use(createPinia())) といったプラグインを組み込んでいきます。app.mount('#app'): 作成したVueアプリケーションインスタンスを、HTMLファイル(通常はpublic/index.html)内のIDがappの要素にマウントします。Vueアプリケーションの描画内容は、この要素の内側に挿入されます。public/index.htmlには<div id="app"></div>のような要素があるはずです。
このファイルは、アプリケーションの開始点として重要ですが、通常は一度設定すればあまり変更しません。
2. テンプレート構文とデータ表示 ({{ }})
src/App.vueファイルを開いてみましょう。単一ファイルコンポーネント(SFC)の構造になっています。まずは<template>タグと<script setup>タグ(または<script>タグ)の内容をシンプルにしてみます。
“`html
{{ greeting }}
{{ message }}
“`
<template>タグ内には、このコンポーネントが表示するHTML構造を記述します。ここで{{ greeting }}や{{ message }}という二重波括弧(Mustache構文)が出てきました。これは「テキスト補間」と呼ばれ、<script>タグ(または<script setup>)で定義されたgreetingやmessageという名前のデータを、この位置にテキストとして表示することを意味します。<script setup>タグ(Composition API)または<script>タグ(Options API)内には、このコンポーネントのJavaScriptのロジックを記述します。ここでは、greetingとmessageというデータ(リアクティブな状態)を定義しています。Options APIの場合はdata()関数の中でオブジェクトとして定義し、Composition APIの場合はref()関数などを使って定義します。Vue 3では<script setup>とComposition APIが推奨されています。<style scoped>タグ内には、このコンポーネントに適用されるCSSスタイルを記述します。scoped属性を付けることで、このスタイルが他のコンポーネントに影響を与えないようになります。
開発サーバーが起動していれば、ブラウザの表示が更新され、「Vue.jsへようこそ!」という見出しとメッセージが表示されているはずです。JavaScript側のgreetingやmessageの値を変更すると、ブラウザの表示も自動的に更新されることを確認できます。これがVue.jsのリアクティブシステムとデータバインディングの基本的な動作です。
3. 属性のバインディング (v-bind または :)
HTML要素の属性(href, src, class, styleなど)に、JavaScriptのデータを動的にバインド(紐付け)したい場合は、v-bindディレクティブを使用します。
“`html
“`
v-bind:href="url"または:href="url":<a>タグのhref属性に、urlというデータ(JavaScript変数)の値を設定します。:title="linkTitle":title属性にlinkTitleの値が設定されます。:class="{ active: isActive, 'text-danger': hasError }":class属性にクラスを動的に適用します。これはオブジェクト構文で、キーがクラス名、値がそのクラスを適用するかどうかの真偽値です。isActiveがtrueならactiveクラスが、hasErrorがtrueならtext-dangerクラスが適用されます。配列構文(:class="[activeClass, errorClass]")も可能です。:style="{ color: textColor, fontSize: fontSize + 'px' }":style属性にスタイルを動的に適用します。これはオブジェクト構文で、CSSプロパティ名をキャメルケース(例:fontSize)またはケバブケース(引用符で囲む、例:'font-size')で指定し、値をバインドします。
v-bindを使うことで、HTMLの静的な属性だけでなく、JavaScriptのデータによって動的に変化する属性値を設定できます。
4. 条件付きレンダリング (v-if, v-else-if, v-else, v-show)
特定の条件が満たされたときだけ要素を表示したり、条件によって表示する要素を切り替えたりしたい場合は、条件付きレンダリングディレクティブを使用します。
“`html
条件付きレンダリング
この段落は v-if で表示されています。
この段落は v-show で表示されています。
“`
v-if: 条件が真の場合のみ、その要素と子要素がDOMに描画されます。条件が偽になると、DOMから完全に削除されます。初期描画や切り替え頻度が低い場合に適しています。v-else-if、v-elseと組み合わせて使うことができます。v-show: 条件が真の場合、要素は表示されます。条件が偽になると、要素はDOMに残りますが、CSSのdisplay: none;スタイルが適用されて非表示になります。初期描画コストはかかりますが、切り替え(表示/非表示の頻繁な切り替え)コストが低い場合に適しています。v-elseやv-else-ifと組み合わせて使うことはできません。
v-ifとv-showは似ていますが、DOM操作の仕組みが異なります。どちらを使うかは、要素の表示/非表示を頻繁に切り替えるかどうかを考慮して判断します。
5. リストレンダリング (v-for)
配列の要素やオブジェクトのプロパティを基に、複数の要素を繰り返し表示したい場合は、v-forディレクティブを使用します。
“`html
リストレンダリング
アイテムリスト
- {{ item.name }} (ID: {{ item.id }})
ユーザーリスト (オブジェクトの繰り返し)
- {{ index + 1 }}. {{ key }}: {{ user.name }} (年齢: {{ user.age }})
数値範囲の繰り返し
- {{ n }}
“`
v-for="item in items":itemsという配列の各要素をitemという変数に代入しながら、その要素に対して指定したHTML構造(ここでは<li>タグ)を繰り返しレンダリングします。:key="item.id":v-forを使用する場合、必ず要素に:key属性を付与する必要があります。key属性には、リスト内の各要素を一意に識別できる値を指定します(通常はデータのIDなど)。Vue.jsはkeyを使って、リストの要素の追加、削除、並べ替えといった変更を効率的に検知し、最小限のDOM操作で画面を更新します。keyがない場合や、ユニークでない値を指定すると、パフォーマンスの問題や予期しない挙動を引き起こす可能性があります。- オブジェクトの繰り返し:
v-for="(value, key, index) in object"のように記述することで、値、キー、インデックスを同時に取得できます。 - 数値範囲の繰り返し:
v-for="n in 5"のように記述すると、1から指定した数値までの連番で繰り返し処理を行えます。
v-forは、動的なリストやテーブルなどを表示する際に非常に役立ちます。
6. イベントハンドリング (v-on または @)
ユーザーの操作(クリック、入力、ホバーなど)によってJavaScriptのメソッドを実行したい場合は、v-onディレクティブを使用します。
“`html
“`
v-on:click="increment"または@click="increment": ボタンがクリックされたときに、<script setup>で定義したincrement関数を実行します。イベントハンドラはメソッド名、あるいはインラインのJavaScript式を指定できます。logEvent($event): インラインでJavaScript式を指定する場合、特殊な変数$eventを使うことで、元のDOMイベントオブジェクトにアクセスできます。- イベント修飾子:
@click.stopのように、.で繋げて修飾子を付けることで、DOMイベントに関する様々な処理をテンプレート側で簡潔に記述できます。.stop:event.stopPropagation()を呼び出し、イベントの伝播を停止します。.prevent:event.preventDefault()を呼び出し、デフォルトのイベント動作(例: リンククリックでのページ遷移、フォーム送信)をキャンセルします。.capture: イベントをバブリングフェーズではなくキャプチャフェーズで処理します。.self: イベントが要素自身で発生した場合のみハンドラを実行します。子要素からのバブリングでは実行されません。.once: イベントハンドラを一度だけ実行します。.passive: スクロールイベントなどでパフォーマンスを改善するために使われます。特にモバイルで役立ちます。
イベントハンドリングとイベント修飾子を組み合わせることで、ユーザーの操作に応じた様々なインタラクティブな処理を柔軟に実装できます。
7. フォーム入力バインディング (v-model)
フォームの入力要素(<input>, <textarea>, <select>)とJavaScriptのデータを双方向でバインディングしたい場合は、v-modelディレクティブを使用します。ユーザーが入力フィールドの値を変更するとJavaScriptのデータが更新され、JavaScriptのデータを変更すると入力フィールドの値が更新されます。
“`html
フォーム入力バインディング (v-model)
テキスト入力
入力された値: {{ inputText }}
テキストエリア
入力された値:
{{ textareaText }}
チェックボックス
同意しましたか? {{ isChecked ? ‘はい’ : ‘いいえ’ }}
好きなフルーツを選んでください:
選んだフルーツ: {{ checkedFruits }}
ラジオボタン
好きな色を選んでください:
選んだ色: {{ pickedColor }}
セレクトボックス
好きな都市を選んでください:
選んだ都市: {{ selectedCity }}
複数の都市を選んでください:
選んだ都市 (複数): {{ selectedCities }}
v-model 修飾子
.lazy: {{ lazyInputText }}
.number (型: {{ typeof numberInput }}): {{ numberInput }}
.trim: “{{ trimInputText }}”
キー修飾子 (@keyup.enter など)
{{ enterStatus }}
“`
v-model="dataName": これだけで、入力要素のvalue属性と、対応するJavaScriptのdataNameというデータの間で双方向バインディングが確立されます。Vue.jsが内部的にv-bind:value="dataName"と@input="dataName = $event.target.value"(あるいは要素に応じた適切なイベント)を組み合わせたものとして処理します。- チェックボックス、ラジオボタン、セレクトボックスでの
v-modelの挙動は、HTMLの要素の種類や属性(value,checked,selected,multipleなど)によって自動的に調整されます。 - v-model 修飾子:
v-model.lazy,v-model.number,v-model.trimのように、.で繋げて修飾子を付けることで、バインディングの挙動をカスタマイズできます。.lazy: デフォルトではinputイベントで同期しますが、.lazyを付けるとchangeイベントで同期するようになります。入力中のリアルタイム同期が不要な場合にパフォーマンス改善に繋がることがあります。.number: ユーザーの入力値を自動的に数値型に変換しようとします。数値として扱いたい入力フィールドで便利です。.trim: ユーザーの入力値の前後にある空白文字を自動的に削除します。
- キー修飾子 (
@keyup.enter,@keydown.escなど):@keyupや@keydownなどのキーボードイベントに.enter,.esc,.spaceなどのキー名を修飾子として付けることで、特定のキーが押されたときだけイベントハンドラを実行できます。
v-modelは、フォーム開発を非常に効率的にしてくれます。手動でDOMのvalueを取得したり、変更を監視したりする手間が省けます。
8. 算出プロパティ (computed) とウォッチャ (watch)
データの変更に応じて別の値を計算したい場合や、特定のデータの変更を監視して副作用を起こしたい場合に、算出プロパティ (computed) やウォッチャ (watch) を使用します。これらはリアクティブシステムと連携して動作します。
“`html
算出プロパティ (Computed)
フルネーム: {{ fullName }}
ウォッチャ (Watchers)
{{ answer }}
“`
- 算出プロパティ (
computed):- テンプレート内で複雑な計算結果を表示したい場合に便利です。
- 依存するデータ(上記の例では
firstNameとlastName)が変更されたときにのみ再計算されます。 - 結果はキャッシュされます。依存データに変更がなければ、何度アクセスしてもキャッシュされた値が返され、再計算は行われません。これにより、計算コストの高い処理のパフォーマンスを改善できます。
- データを返すための関数(getter)として定義しますが、テンプレートからはプロパティのようにアクセスします(例:
{{ fullName }})。 - デフォルトではgetterのみですが、setterを定義して双方向バインディングのようにも使えます(高度な使い方)。
- ウォッチャ (
watch):- 特定のデータの変更を監視し、データが変更されたときに非同期処理やコストのかかる処理、あるいはDOM操作などの「副作用」を実行したい場合に便利です。
- データが変更されるたびに実行されます。キャッシュはありません。
- 変更前後のデータ(
newValue,oldValue)を受け取ることができます。 - デフォルトでは初回読み込み時には実行されません。
immediate: trueオプションを指定すると初回実行されます。 - オブジェクトや配列を監視する場合、デフォルトでは参照の変化のみを監視します。
.deep: trueオプションを指定すると、ネストしたプロパティの変更も監視できます(ただしパフォーマンスに影響する場合があります)。
算出プロパティは「データの派生」に、ウォッチャは「データの変更をトリガーとした処理」に適しています。それぞれの特性を理解して使い分けることが重要です。多くの場合、データの派生は算出プロパティで事足ります。ウォッチャが必要になるのは、非同期処理の実行や、Vueのリアクティビティシステム外のAPIとの連携など、より具体的な副作用を伴う場合です。
コンポーネントの基本
ここまでApp.vueという一つのファイルにすべてのコードを書いてきましたが、実際のアプリケーションでは、UIを再利用可能な部品に分割して開発するのが一般的です。これがコンポーネント指向開発です。
Vue.jsでは、単一ファイルコンポーネント(SFC, .vueファイル)を使ってコンポーネントを定義し、それを組み合わせてアプリケーションを構築します。
1. 単一ファイルコンポーネント (SFC) の構造
先ほども少し触れましたが、.vueファイルは以下の3つのブロックで構成されます。
“`html
これはカスタムコンポーネントです。
メッセージ: {{ myMessage }}
内部カウンター: {{ counter }}
“`
<template>: コンポーネントの見た目(HTML構造)を定義します。ここには必ず一つのルート要素が必要です(Vue 3では複数のルート要素も可能ですが、慣習として一つにまとめることが多いです)。<script setup>: コンポーネントのロジック(データ、算出プロパティ、ウォッチャ、メソッドなど)を定義します。Vue 3で推奨されるComposition APIスタイルで、<script setup>を使うと、ref,computed,watch,defineProps,defineEmitsといったComposition APIの機能や、インポートしたモジュールがテンプレート内で自動的に使用できるようになります。Options APIを使う場合は<script>タグ内にexport default { ... }の形式で記述します。<style scoped>: コンポーネントに適用するCSSスタイルを定義します。scoped属性を付けることで、スタイルがこのコンポーネントだけに適用され、他のコンポーネントのスタイルを汚染する心配がなくなります(CSSスコープ)。
2. コンポーネントの登録と利用
作成したコンポーネントは、他のコンポーネント(通常は親コンポーネント)の中で利用する必要があります。
src/componentsフォルダの中に、例えばMyComponent.vueというファイル名で上記のコンポーネントを作成したとします。これをsrc/App.vueの中で利用してみましょう。
“`html
MyApp
これはAppコンポーネントです。
子コンポーネントからカウンターが {{ totalIncrementedCount }} 回増加しました。
クリック
me!
“`
import MyComponent from './components/MyComponent.vue';:MyComponent.vueファイルをインポートします。Vite/Vue 3では、<script setup>を使用している場合、このようにインポートしたコンポーネントはテンプレート内でコンポーネント名(ここではMyComponent)としてそのまま利用できます(ローカル登録)。<MyComponent ... />: テンプレート内で、インポートしたコンポーネントをカスタムタグとして使用します。タグ名は、通常PascalCase(例:MyComponent)やkebab-case(例:my-component)で記述します。Vueのテンプレートではkebab-caseが推奨されることが多いですが、単一ファイルコンポーネントではPascalCaseもよく使われます。- ローカル登録: この例のように、利用したいコンポーネントを各コンポーネントファイル内でインポートして使用する方法を「ローカル登録」と呼びます。これはVue 3で推奨される方法です。
- グローバル登録: 非推奨ですが、アプリケーション全体でどこでも使えるように一括登録する方法もあります(
main.jsなどでapp.component('ComponentName', ComponentDefinition)のように登録)。ただし、これは未使用のコンポーネントも含めて最終的なJavaScriptファイルに含まれてしまうため、アプリケーションサイズが大きくなる可能性があります。ローカル登録の方が、必要なコンポーネントだけがロードされるため、パフォーマンス面で有利です。
このように、コンポーネントをインポートしてテンプレートで使うことで、UIを部品として組み立てていくことができます。
3. Props によるデータの受け渡し (親 → 子)
親コンポーネントから子コンポーネントへデータを受け渡すには、Props(プロパティ)を使用します。子コンポーネントはPropsを介して親からデータを受け取り、そのデータに基づいて自身の表示や振る舞いを変更します。
上記の例で、MyComponentは親(App.vue)からmy-messageというデータを受け取っています。
-
子コンポーネント (
MyComponent.vue):<script setup>内でdefinePropsヘルパーを使って、受け取るPropsを定義します。引数には、Props名とその型、必須かどうかなどを指定したオブジェクトを渡します。- 定義したPropsは、
propsオブジェクト(definePropsが返す値)のプロパティとしてアクセスできます(例:props.myMessage)。Composition APIで直接分割代入する場合はリアクティブ性が失われる可能性があるため注意が必要ですが、toRefsなどの関数を使う方法や、definePropsをそのまま返す方法などがあります。上記の例ではprops.myMessageとして使っています。 - Propsとして受け取ったデータは、子コンポーネント内で変更してはいけません(単方向データフローの原則)。もし子コンポーネントでPropsの値を変更する必要がある場合は、その値を基にした別のデータを用意するか、イベントを発行して親に変更を依頼します。
-
親コンポーネント (
App.vue):- 子コンポーネントを使用する際に、カスタムタグの属性としてProps名を指定し、渡したいデータをバインドします。
- 静的な値を渡す場合はそのまま属性値を記述します (
my-message="Hello from App!")。 - JavaScriptの変数の値を渡す場合は、
v-bindまたはそのショートカット:を使ってバインドします (:my-message="parentMessageVariable")。ケバブケースのProps名(my-message)は、JavaScript側ではキャメルケース(myMessage)として扱われます。
Propsを使うことで、親コンポーネントは子コンポーネントに「何を」表示・処理するかを指示できます。これは、コンポーネントの再利用性を高める上で非常に重要な仕組みです。
4. Emits によるイベント通知 (子 → 親)
子コンポーネントで何かイベントが発生したときに、親コンポーネントにそのことを通知したい場合は、カスタムイベントを発行(emit)します。親コンポーネントは、そのカスタムイベントを購読(listen)して、適切な処理を行います。
上記の例で、MyComponentは内部カウンターが増加したときに親(App.vue)に通知しています。
-
子コンポーネント (
MyComponent.vue):<script setup>内でdefineEmitsヘルパーを使って、発行するイベント名を定義します。これは、親コンポーネントがどのイベントを購読できるか、あるいはイベント名に誤字がないかなどのコードの可読性や検証に役立ちます。引数には、発行するイベント名の配列を渡します。- イベントを発行したい箇所で、
emits関数(defineEmitsが返す関数)を呼び出します。第一引数にイベント名、第二引数以降に親コンポーネントに渡したいデータを指定します(例:emits('counter-incremented', counter.value))。
-
親コンポーネント (
App.vue):- 子コンポーネントを使用する際に、
v-onまたはそのショートカット@を使って、子コンポーネントが発行するカスタムイベント名を指定し、そのイベントが発生したときに実行したいメソッドを紐付けます (@counter-incremented="handleIncrement")。 - 子コンポーネントから渡されたデータは、イベントハンドルメソッドの引数として受け取ることができます(例:
handleIncrement(count))。
- 子コンポーネントを使用する際に、
Propsが親から子への一方通行のデータフローであるのに対し、Emitsは子から親へのイベント通知という形でのコミュニケーション手段です。この「Props down, Events up」というデータフローの原則を守ることで、アプリケーションの状態の変化を予測しやすく、デバッグしやすいコードを書くことができます。
5. Slot によるコンテンツの配布
コンポーネントを再利用する際、そのコンポーネントの「中身」を親コンポーネント側で柔軟に指定したい場合があります。例えば、ボタンコンポーネントのラベルテキストはPropsで渡せますが、ラベルの中にアイコンや複雑なHTML構造を含めたい場合、Propsでは対応が難しいです。このようなケースでSlot(スロット)を使用します。
Slotは、子コンポーネント内の特定の場所に、親コンポーネントから提供されるコンテンツを挿入するための仕組みです。
src/componentsフォルダの中に、例えばFancyButton.vueというファイル名で以下のコンポーネントを作成してみましょう。
“`html
“`
このFancyButtonコンポーネントは、<template>内に<slot></slot>タグを持っています。このタグが、親からコンテンツが挿入される「スロット」の場所を示します。
次に、これをApp.vueで利用します(先にApp.vueのコードにimport FancyButton from './components/FancyButton.vue';と<FancyButton>タグを追加しておいた部分です)。
“`html
Slot の例
クリック
me!
シンプルなボタン
“`
App.vueで<FancyButton>タグを使用する際に、開始タグと終了タグの間に記述したHTMLコンテンツ(<span>クリック</span><strong> me!</strong>など)が、FancyButton.vue内の<slot></slot>の位置にレンダリングされます。
名前付きスロット (Named Slots):
一つのコンポーネント内に複数のスロットが必要な場合があります。例えば、カードコンポーネントでヘッダー、本文、フッターそれぞれに異なるコンテンツを挿入したい場合などです。このような場合は、名前付きスロットを使用します。
-
子コンポーネント (
Card.vue):
html
<!-- src/components/Card.vue -->
<template>
<div class="card">
<div class="card-header">
<!-- 名前付きスロット: 'header' -->
<slot name="header"></slot>
</div>
<div class="card-body">
<!-- デフォルトスロット (名前なし) -->
<slot></slot>
</div>
<div class="card-footer">
<!-- 名前付きスロット: 'footer' -->
<slot name="footer"></slot>
</div>
</div>
</template>
<script setup></script>
<style scoped>
.card { border: 1px solid #eee; border-radius: 4px; margin: 10px; }
.card-header { padding: 10px; border-bottom: 1px solid #eee; }
.card-body { padding: 10px; }
.card-footer { padding: 10px; border-top: 1px solid #eee; }
</style>
<slot name="スロット名"></slot>のようにname属性を付けてスロットを定義します。名前を付けない<slot></slot>は「デフォルトスロット」と呼ばれます。 -
親コンポーネント (
App.vue) での利用:
“`html
…<h2>名前付きスロットの例</h2> <Card> <!-- v-slot:header は #header と省略できる --> <template #header> <h3>カードタイトル</h3> </template> <!-- デフォルトスロットのコンテンツ --> <p>カードの本文コンテンツです。</p> <template #footer> <button>詳細を見る</button> </template> </Card>
``
親コンポーネント側では、タグにv-slot:スロット名またはそのショートカット#スロット名属性を付けて、どのスロットにどのコンテンツを挿入するかを指定します。デフォルトスロットには、`タグで囲まずに直接コンテンツを記述できます。
Slotを使うことで、コンポーネントの内部構造(見た目)は固定しつつ、表示するコンテンツだけを親コンポーネント側で自由に変更できるようになります。これにより、コンポーネントの柔軟性と再利用性がさらに向上します。
Slotのデフォルトコンテンツ:
子コンポーネントで、親からコンテンツが提供されなかった場合に表示するデフォルトコンテンツを設定することもできます。これは、<slot>タグの開始タグと終了タグの間に記述します。
“`html
``App.vueでのようにコンテンツを指定した場合、そのコンテンツが挿入されます。もし
Vue.jsの高度なトピック(入門レベルで触れる程度)
ここまでに説明した基本機能をマスターすれば、Vue.jsを使った基本的なアプリケーション開発は十分に可能です。しかし、実際の開発では、さらに複雑な機能や大規模なアプリケーションに対応するためのライブラリや概念が必要になります。ここでは、それらを簡単に紹介し、今後の学習の方向性を示します。
1. Vue Router (ルーティング)
単一ページアプリケーション(SPA)では、画面遷移はサーバーからのページ読み込みではなく、JavaScriptによるDOMの動的な書き換えで行われます。このとき、ブラウザのアドレスバーのURLを管理し、URLに応じて表示するコンポーネントを切り替える役割を担うのが「ルーティング」ライブラリです。Vue.jsにおいては、公式の「Vue Router」が広く使われています。
Vue Routerを使うと、URLパスとコンポーネントのマッピングを定義し、ナビゲーションリンク(router-linkコンポーネント)やプログラムによるナビゲーション(router.pushメソッド)を使って、ページ遷移を実装できます。
Viteでプロジェクト作成時にVue Routerを選択した場合、src/router/index.jsのようなファイルにルーティング設定が定義されています。
“`javascript
// src/router/index.js の例
import { createRouter, createWebHistory } from ‘vue-router’;
import HomeView from ‘../views/HomeView.vue’; // Homeページのコンポーネント
const router = createRouter({
// HTML5 History API を使用 (URLに # がつかない)
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: ‘/’, // ルートパス
name: ‘home’,
component: HomeView // 対応するコンポーネント
},
{
path: ‘/about’, // ‘/about’ パス
name: ‘about’,
// コンポーネントは遅延ロード (必要になったら読み込む)
component: () => import(‘../views/AboutView.vue’)
}
]
});
export default router;
“`
そして、通常src/App.vueのテンプレートで<router-view>コンポーネントを配置し、そこに現在のURLに対応するコンポーネントがレンダリングされるようにします。ナビゲーションリンクは<router-link to="/about">About</router-link>のように記述します。
2. Pinia (状態管理)
アプリケーションの規模が大きくなり、複数のコンポーネント間で複雑なデータを共有したり、アプリケーション全体で一貫した状態(例: ログインユーザー情報、カートの中身、テーマ設定など)を管理したりする必要が出てくると、「状態管理」の仕組みが必要になります。
Piniaは、Vue.jsの公式状態管理ライブラリとして推奨されています。これは、Vuex(Vue 2で標準だった状態管理ライブラリ)の後継であり、よりシンプルで使いやすい設計になっています。
Piniaでは、「ストア (Store)」と呼ばれる独立した領域にアプリケーションの状態を集約します。各ストアは、状態データ(state)、状態を変更するメソッド(actions)、状態から派生したデータ(getters)を持つことができます。
Viteでプロジェクト作成時にPiniaを選択した場合、src/storesフォルダ内にストア定義ファイルが作成されます。例えば、カウンター機能を管理するストアは以下のようになります。
“`javascript
// src/stores/counter.js の例
import { ref, computed } from ‘vue’;
import { defineStore } from ‘pinia’;
// ‘counter’というIDでストアを定義
export const useCounterStore = defineStore(‘counter’, () => {
// 状態 (state)
const count = ref(0);
// 算出プロパティ (getters)
const doubleCount = computed(() => count.value * 2);
// アクション (actions)
function increment() {
count.value++;
}
// 外部に公開する状態、算出プロパティ、アクションを返す
return { count, doubleCount, increment };
});
``useCounterStore()`のように呼び出して利用できます。Piniaを使うことで、コンポーネント間のデータフローが整理され、状態管理がより見通しやすくなります。
このストアは、どのコンポーネントからでも
3. Composition API と Options API
Vue.jsには、コンポーネントのロジックを記述するための2つのスタイルがあります。
-
Options API: Vue 2から存在し、Vue 3でも利用可能なスタイルです。
data,methods,computed,watch,props,emitsなどの「オプション」を使ってコンポーネントの各機能を整理します。初心者にとっては、データの定義はdataオプション、メソッドの定義はmethodsオプション、のように役割ごとにコードを記述するため、分かりやすいと感じることが多いかもしれません。
javascript
// Options API の例
export default {
props: { /* ... */ },
emits: [/* ... */],
data() {
return {
// データ
count: 0
}
},
computed: {
// 算出プロパティ
doubleCount() {
return this.count * 2;
}
},
watch: {
// ウォッチャ
count(newValue, oldValue) {
console.log(`count が ${oldValue} から ${newValue} に変更されました`);
}
},
methods: {
// メソッド
increment() {
this.count++;
}
}
} -
Composition API: Vue 3から本格的に導入され、現在推奨されているスタイルです。関数(
ref,reactive,computed,watch,defineProps,defineEmitsなど)を組み合わせてコンポーネントのロジックを構築します。特に、関連するロジック(例: ある機能に関連するデータ、メソッド、ウォッチャなど)をまとめて記述できるため、機能ごとにコードを整理しやすく、大規模なコンポーネントや、複数のコンポーネント間でロジックを再利用する場合(Composablesと呼ばれる仕組み)に非常に強力です。src/App.vueやsrc/components/MyComponent.vueの<script setup>で記述してきたのがこのスタイルです。
“`javascript
// Composition API の例 (setup 関数内、あるいは