
Vue 3 Composition API入門
https://tomosta.jp/2022/06/vue3-begin
Vue 3 Composition API入門
記事を共有:
Vue.jsは、JavaScriptライブラリとしてReactと共に人気のあるライブラリです。特に2021年に登場した最新の「Vue 3」からは「Composition API」という新しい開発手法が登場しました。
これは、それまでのVue.jsの開発手法(これをOptions APIといいます)では、かなり独特だったプログラムの書き方が、かなりJavaScript標準の書き方に近づいたもので、Vue.jsに馴染めなかった人でも、すんなり導入できるスタイルに変化しました。
本記事では、そんなComposition APIを利用したVue 3の開発手法を紹介しながら、簡単なToDoツールを開発していきましょう。
Vue 3のプロジェクトを作成しよう
npmを利用しよう
Vue 3は、HTMLファイルに後から組み込むこともできますが、npmを利用してプロジェクトを作成することもできます。今回は、この方法を利用するためnpmの環境を整えましょう。Node.jsをインストールします。
インストールが終わったら、ターミナル(Windowsの場合は、Microsoft TerminalまたはPowershell)を起動して、以下のコマンドを入力します。
node -v
Copy
これで、図のようにバージョン番号が表示されていれば、正しくインストールされています。

後は、エディターとしてVisual Studio CodeとウェブブラウザーにGoogle Chrome等を導入しておくと、開発しやすいでしょう。
プロジェクトを作成しよう
それでは、Vue 3のプロジェクトを作成しましょう。プロジェクトを作成する場所(ここではDesktop)に移動して、プロジェクトを作成します。
cd Desktop
npm init vue@lates
Copy

すると、次のようなものをあわせてインストールするかを聞かれます。ここでは、すべて「No」を選ぶと良いでしょう。プロジェクト名はてきとうなものを入力していきます。
- TypeScript – JavaScriptの上位互換言語
- JSX – HTMLをJavaScript内で利用できる
- Vue Router – ページ遷移のサポート
- Pinia – 「状態管理」と呼ばれるデータの保管などに使われる
- Vitest – テストフレームワーク
- Cypress – 同上
- ESLint – コードの検査などを行う

こうしてコマンドを実行すると、各種ファイル群がダウンロードされます。ここで作成したフォルダーを、Visual Studio Code(VSCode)で開いておきましょう。

開発サーバーを起動しよう
Vue 3のプロジェクトには、簡易的なウェブサーバーが同梱されていて、これを起動しながら開発ができます。VSCodeで「ターミナル→新しいターミナル」メニューでターミナルを起動したら、次のコマンドを打ち込みましょう。
npm install
npm run dev
Copy
アドレスが表示されれば、起動完了です。

ここで表示されているアドレスをブラウザーで開いてみましょう。次の画面が表示されます。

ファイルを変更してみよう
それでは、作られたファイル群を確認していきましょう。次のようなフォルダーやファイルが生成されています。
- node_modules – Node.jsのモジュール群がインストールされます
- public – 画像ファイルなどのリソースファイルが格納されます
- src – ソースファイルが格納されます
- src/assets – CSSや画像ファイルなど、ソース内で使われるリソースファイルが格納されます
- src/components – コンポーネント(後述)が格納されます
- src/App.vue – プロジェクトのメインとなるファイル
- src/main.js – メインとなるJavaScriptファイル
- index.html – ブラウザーに読み込まれる最初のHTMLファイル
この他、環境設定ファイルなどがありますが、基本的には「src」フォルダー内のファイルを編集していきます。
ここでは、App.vueを編集してみましょう。11行目付近に「You did it!」というメッセージが記述されています。これは、ブラウザーに表示される画面の左側に表示されるメッセージです。

これを、「ともすた」等に書き換えてみましょう。ファイルを保存すると、ブラウザーもすぐに変化します。

これは、開発サーバーがファイルの変更を監視していて、必要に応じて再読込などするためです。
ビルドしよう
こうして、.vueという拡張子のファイルを編集していくことでプログラムを作成するのですが、これらのファイル群はそのままではウェブサーバーで公開することはできません。プロジェクトが完成した「ビルド」という作業が必要になります。
まずは、開発サーバーを終了しましょう。ターミナル上で「Ctrl+C」を押します。代わりに、次のコマンドを打ち込みます。
npm run build
Copy
すると、「dist」というフォルダーが自動的に増えます。

ここに、HTMLやJavaScript等のファイルが生成されるため、これをウェブサーバーに転送して公開できます。
開発するときには、改めて開発サーバーを起動しておきましょう。
npm run dev
Copy
Vueの新しい開発手法 Composition API
Vue 3では、従来のプログラムスタイルでも開発ができますが、新しくよりJavaScriptらしい開発スタイルでプログラミングができるようになりました。これを、「Composition API」といいます。(従来の開発スタイルをOptions APIといいます)
ここでは、そんなComposition APIを利用した開発を大変してみましょう。
templateを準備しよう
まずは、前回の記事を参考にVueのプロジェクトを作成してください。
最初に画面には「src」フォルダーの「App.vue」ファイルが表示されます。今はサンプルのプログラムが書き込まれているので、一度これをすべて削除してしまいましょう。ブラウザー上の表示も真っ白の画面に変わります。

.vueファイルにはHTMLを記述できますが、その際に前後を<template>
タグで囲む必要があります。この中に、HTMLを記述していきましょう。
<template>
<h1>Vue 3</h1>
</template>
Copy
これでファイルを保存すると、ブラウザーの表示内容も変化します。

Options APIでの書き方
ではまずは、Options APIを復習しておきましょう。例えば、<template>
内に
<p>1 + 1 = </p>
Copy
と記述し、この最後に足し算の答えを表示してみましょう。Options APIの場合は、次のようにファイルの最後に追加します。
<script>
export default {
data() {
return {
answer: 2
}
}
}
</script>
Copy
Options APIでは「data」という定義の中で、HTML内で利用したい内容を扱うことができます。表示するには、<template>
内に、次のように「マスタッシュ構文」を記述します。
<p>1 + 1 = {{ answer }}</p>
Copy
これで、画面に結果が反映されます。
マスタッシュ構文とは「{{」という記号で、扱いたいデータの名前などを記述するもので、これによって画面に「answer」の内容である「2」が表示されるようになります。

従来のVueはこのような開発スタイルで開発してのですが、書き方がかなり独特で習得に手間がかかっていました。そこで、Composition APIというより素直な書き方が採用されました。今作成した<script>
タグは削除しましょう。
Composition APIで記述しよう
今度は、ファイルの先頭に次のように追加しましょう。
<script setup>
const answer = 2
</script>
Copy
これで、先ほどのマスタッシュ構文が正しく機能して、次のように画面に表示されます。(なお、実際にはこの記述では少し足りない部分がありますが、それについては後述します)

<script>
タグに「setup」という属性が必要になるので気をつけてください。
Composition APIの場合、実際のプログラムはECMAScriptの定数の宣言と同様です。「const」宣言の後に利用したい定数名とその値を設定するだけで、マスタッシュ構文で使うことができます。
computedで計算しよう
現状では、「answer」には直接「2」が代入されているため、これではプログラムを作って意味がありません。ここは、実際に「1+1」の計算をして、その結果を画面に表示してみましょう。Vueで計算式などを作る場合はcomputed
構文を利用します。次のように変更しましょう。
<script setup>
import { computed } from 'vue'
const answer = computed(() => {
return 1 + 1
})
</script>
Copy
これで画面には、「2」と表示されます。試しに別の計算式を入れてもきちんと計算してくれるのが分かります。

ここではcomputed
を利用しましたが、JavaScriptではこのように他で定義されたものを使うときに「モジュール」というものをインポートして利用することがよくあります。この書き方も覚えておきましょう。
HTMLを表示しよう
Vueで定義した定数は、安全性のためにそのままではHTMLなどを画面に表示することはできません。例えば、次のプログラムを作成してみましょう。
<script setup>
...
const message = 'ようこそ <strong>ともすた</strong>さん'
</script>
<template>
...
<p>{{ message }}</p>
</template>
Copy
この場合、次のようにHTMLタグがそのまま表示されてしまいます。

これを防ぐには、マスタッシュ構文を使わずにv-html
という属性のようなものを利用して、次のように変更します。
<p v-html="message"></p>
Copy
これで、HTMLを展開して表示できるようになります。

このv-
から始まるHTML属性のようなものを「ディレクティブ」といい、VueがHTMLを制御する時によく利用します。なお、マスタッシュ構文も実はv-text
というディレクティブでも同じように動作します。
<p v-text="message"></p>
Copy
この場合は、HTMLタグがそのまま表示されます。

v-bindでHTMLのstyle属性を動的に書き換えよう
例えば、HTMLのstyle
属性の内容をVueで書き換えたいとしましょう。この場合、次のように属性の中にマスタッシュ構文を使うことはできません。
<p v-text="message" style="color: {{ welcomeColor }}"></p>
Copy
代わりにこの場合はv-bind
ディレクティブを利用します。まずは、welcomeColor
という色を定義しましょう。
<script setup>
...
const welcomeColor = 'red'
</script>
Copy
そして、style
属性は次のように変更します。
<p v-text="message" v-bind:style="{ color: welcomeColor }"></p>
Copy
これにより、文字の色がwelcomeColor
で定義した内容に変わります。

v-bind
ディレクティブを利用すると、属性の値に変数を利用できるようになるというわけです。
ハイフン付のプロパティには注意
1つ注意が必要なのは、プロパティにハイフン記号が必要なbackground-color
等です。これは、JavaScriptの処理の関係で正しく動作しなくなるため、ハイフンを取り除いて、代わりにその後最初の文字を大文字にする「キャメル式」と呼ばれる記法に変換します。
<p v-text="message" v-bind:style="{ backgroundColor: welcomeColor }"></p>
Copy
または、プロパティ自体をクオーテーション記号で囲むこともできます。複数のプロパティをカンマ区切りで並べたり、値を直接指定することもできます。
<p v-text="message" v-bind:style="{ 'background-color': welcomeColor, 'color': 'white' }"></p>
Copy

v-bindの省略記法
v-bind
ディレクティブは、非常によく利用するため省略記法があります。次のように:
を記述するだけで代わりになります。
<p v-text="message" :style="{ 'background-color': welcomeColor, 'color': 'white' }"></p>
Copy
フォームなどと連携するv-model
今度は、テキストフィールドパーツを利用してみましょう。次のようにinput
要素を追加します。
<template>
...
お名前は?: <input type="text" size="30">
...
</template>
Copy
ここで、入力された名前をVueで扱いたいとしましょう。そこでまずは定数を準備します。
<script setup>
...
const myname = ''
</script>
Copy
これまではv-html
やv-text
で連携していましたが、この場合はテキストフィールドに入力した内容を反映する事ができません。テキストフィールドなどと双方向に連携したい場合はv-model
を利用します。
お名前は?: <input type="text" size="30" v-model="myname">
Copy
これにより、テキストフィールドに入力した内容がmyname
に反映され、他の場所で利用できるようになります。
refで宣言しよう
その前に、実は今のプログラムでは正しくHTML側とVue側で値のやり取りができません。Vueで定数を宣言する場合はref
という宣言を使う必要があります。次のように変更しましょう。
<script setup>
import { ref } from 'vue'
...
const myname = ref('')
</script>
Copy
これで、双方向に連携ができるようになります。それでは、ここで入力した名前を画面に表示してみましょう。
<p v-html="myname" ...>
Copy

メッセージを組み立てよう
それでは、ここまでのプログラムを組み合わせて、テキストフィールドに入力した名前を使って「ようこそ○○さん」と表示するプログラムを作成してみましょう。それには、message
をcomputed
で動的に生成します。
const message = computed(() => {
return 'ようこそ <strong>' + myname.value + '</strong>さん'
})
...
<template>
<p v-html="message" ...>
</template>
Copy
これで完成です。画面には入力した名前が表示されます。

プログラム内でref
を使って宣言した定数の内容を利用する場合は.value
として取得する必要があります。このあたりは、少しJavaScriptとは違った書き方が必要になるので気をつけましょう。
とはいえ、Composition APIでのVueのプログラムの書き方は、かなり素直な書き方に変わっていることが分かります。プログラムを作りやすくなったと言えるでしょう。
ボタンのクリックに反応するイベント定義
Vueでのプログラミング開発は、ユーザーがなにかの操作をしたとき(イベントといいます)に、それに反応するプログラムを記述するというのが主になります。これを「イベントドリブン」などといいますが、ここではVueでのイベント定義について紹介しましょう。
拡張機能で開発しやすくしよう
その前に、Vueでの開発を補助する拡張機能をVSCodeとGoogle Chromeにインストールしておきましょう。
Visual Studio CodeでVue用の拡張機能をインストールしよう
Visual Studio Code(VSCode)でVueの開発をする際、拡張子が「.vue」だとそのままではJavaScriptやHTMLとして認識してくれません。そこで、拡張機能をインストールして、開発しやすくしましょう。
VSCodeの拡張機能画面で「vue」などのキーワードで検索をします。次のプラグインが見つかりますので、これをインストールしましょう。

これで、色分けされるようになりました。

Google ChromeにもVue.js devtoolsをインストールしよう
今度は、Google ChromeでもVueの開発をしやすくする拡張機能をインストールしておきましょう。
インストールした後、Vueで開発したページを表示すると、ツールバー上のボタンが緑色になります。

そして、開発者ツールに「Vue」というタブが増えます。

ここで、Vueのさまざまな情報を確認でき、開発しやすくなります。

イベント定義をしよう
それではイベントを定義してみます。新しいファイルを作成していきましょう。前回までのプログラムをすべて削除します。そして、次のように入力してフォームを追加してみましょう。
<template>
<input type="text" size="30"> <button>+1</button>
</template>
Copy
すると、画面にはテキストフィールドとボタンが表示されました。

では、このボタンをクリックしたらテキストフィールド内の数字が加算されるプログラムを作成してみましょう。
v-modelで数値を定義しよう
まずは、テキストフィールドの数字をプログラムで扱えるように、v-model
で定義しましょう。まずは、ファイルの上部で次のように準備します。
<script setup>
import { ref } from 'vue'
const number = ref(0)
</script>
<template>
...
Copy
これで、number
という値を使えるようになりました。これを、v-model
でテキストフィールドに割り当てます。
...
<input type="text" size="30" v-model="number">...
...
Copy
これで、画面上のテキストフィールドに「0」が表示されるようになりました。

なお、前節でインストールしたVue.js devtoolsがあれば、開発者ツールでも「number」を確認できます。

ボタンをクリックしたときのイベントを定義しよう
続いて、ボタンをクリックされたときのイベントを定義しましょう。v-on
というディレクティブを利用します。
<button v-on="">+1</button>
Copy
この時に呼び出す処理は、<script>
タグ内に次のように宣言します。
const add = () => {
}
Copy
これで、add
という関数が定義されました。JavaScriptの「アロー宣言」という方法で宣言しています。
処理の内容は、先ほど定義したnumber
に1を加算するという処理を作ります。
const add = () => {
number++
}
Copy
「++」というのは、「インクリメント」といって1を加算するという処理です。そしたら、ここで定義したイベントを呼び出しましょう。
<button v-on="add()">+1</button>
Copy
これで完成です。動作させると、テキストフィールド内の数字が加算されるようになりました。

クリックする度に加算されていきます。
v-onの省略
v-on
ディレクティブも利用する機会が多いため、前回紹介したv-bind
等と同様で省略形が準備されています。@
を記述します。
<button @click="add()">...
Copy
こちらの書き方に慣れておくと良いでしょう。

v-forで繰り返し同じ処理を記述しよう
例えば、ToDoツールなどで「やることリスト」に入っている内容をすべて画面に表示したいといった場合に、同じ作業を繰り返し行ったりします。そのような時に使えるのがv-for
という構文です。早速使ってみましょう。
HTMLを準備しよう
まずは、ここまでに作成したApp.vue
の内容はすべて削除し、次のように記述します。
<template>
<input type="text" size="30">
<button>追加</button>
</template>
Copy

では、このテキストフィールドに入力した内容を、やることリスト(配列)に記録して、画面に表示していきましょう。
v-modelを定義しよう
それでは、テキストフィールドの内容とプログラムをつなげるために、v-model
を定義しましょう。ファイルの先頭に、次のように追加します。
<script setup>
import { ref } from 'vue'
const newTodo = ref('')
</script>
...
Copy
それから、テキストフィールドのHTMLには、v-model
ディレクティブを追加します。
<input type="text" size="30" v-model="newTodo">
Copy
これで、反映するようになりました。テキストフィールドになにか入力してみましょう。デベロッパーツールの「Vue」タブを確認すると、反映されていることが確認できます。

アクションを定義しよう
続いて、「追加」ボタンをクリックしたらテキストフィールドの内容を配列に格納しましょう。プログラムに次のように追加します。
<script setup>
import { ref } from 'vue'
const todos = ref([])
const newTodo = ref('')
const addTodo = () => {
todos.value.push(newTodo.value)
}
</script>
Copy
ここでは、todos
という配列を準備しました。そして、addTodo
というアクションを定義し、その中で、ここで準備した配列のpush
メソッドを使って、要素を追加しています。追加するないようは、テキストフィールドに入力されている内容です。
そしたら、ボタンをクリックした時のイベントとして、今定義したaddTodo
を割り当てましょう。
<button @click="addTodo()">追加</button>
Copy
これで、テキストフィールドになにかを入力して「追加」ボタンをクリックすると、配列に追加されることが分かります。

こうして、次々に配列に値を入れることができます。
配列の内容を表示しよう
それでは、ここで準備した配列の内容を表示していきましょう。まずは、HTMLを準備します。
...
<ul>
<li>あれをやる</li>
<li>これをやる</li>
</ul>
...
Copy

これを実際に配列の内容に置き換えていきましょう。<li>
タグにv-for
ディレクティブを追加します。
...
<li v-for="(todo, i) in todos">{{ i }}. {{ todo }}</li>
...
Copy
in
という構文は、todos
という配列の内容を1件取りだしてtodo
に内容を、i
にその順番を格納するという構文です。そしてこれは、配列の内容がすべて取り出されるまで繰り返し行われます。
これで、テキストフィールドになにかを入力すると、下にリストが表示されるようになります。

なお、v-for
を使う場合はその行を特定するためにkey
という値をv-bind
する必要があります。そしてここには、他と重複しない値を挿入します。そのため、先ほど取りだしたi
を使いましょう。次のように変更します。
<li v-for="(todo, i) in todos" v-bind:key="i">{{ i }}. {{ todo }}</li>
Copy
入力された内容を削除しよう
現状、テキストフィールドの内容を追加しても、入力した内容がまだテキストフィールドに残ってしまうため、消さなければなりません。これを、自動で削除されるようにしましょう。addTodo
を次のように変更します。
...
const addTodo = () => {
todos.value.push(newTodo.value)
newTodo.value = ''
}
...
Copy

なお、確認できたら番号の表示は不要なので、これを削除して次のようにしておきましょう。
<li v-for="(todo, i) in todos" v-bind:key="i">{{ todo }}</li>
Copy
Vue 3で条件によって要素を表示・非表示しよう – v-if / v-else
ここでは、ToDoの削除機能を実装しましょう。まずは、リストの右端に削除ボタンの代わりに「x」を記述します。
<li v-for="(todo, i) in todos" v-bind:key="i">{{ todo }} x</li>
Copy

続いて、イベントを定義していきましょう。まずはremoveTodo
というメソッドを準備しておきます。
<script setup>
...
const removeTodo = (index) => {
todos.value.splice(index, 1)
}
</script>
Copy
splice
というのは、配列から様子を削除するためのメソッドで、ここでは指定された要素を1件配列から削除することで、ToDoを削除したというわけです。
続いて、削除ボタンにイベントを定義していきます。
<li ...><span @click="removeTodo(i)">x</span></li>
Copy
これで、動作するようになります。ただし、現状では削除ボタンがクリックできるのかが判別しにくいので、スタイルシートを使ってマウスカーソルの形状を変えておきましょう。

<li ...><span @click="removeTodo(i)" style="cursor: pointer">x</span></li>
Copy
これで分かりやすくなりました。

これで削除が機能するようになります。ToDoを登録して削除すると、実際にリストから消えることが確認できます。
ToDoがないときは、メッセージを表示しよう
ToDoが一件もないときは、現状では空の<ul>
タグが出力されてしまい、画面が真っ白になってしまいます。これではツールとして分かりにくいので、ここではその旨のメッセージを表示するようにしましょう。
これには、条件に従って要素の表示・非表示を制御できるv-if
というディレクティブを利用します。
まずは、<ul>
タグに次のように追加しましょう。
<ul v-if="todos.length > 0">
...
</ul>
Copy
これで、ToDoが1件もない場合は出力しないという指定です。ToDoの配列は.length
というプロパティで現在の件数を知ることができます。これが、0よりも大きい場合にだけ出力されるようになります。
これで画面を表示して、HTMLのソースを確認すると、<ul>
タグの代わりにVueのコメントタグが挿入されています。

そして、ToDoを追加すると<ul>
タグから含めて出力されるようになります。
「そうではない場合」を表すv-else
v-if
で指定した条件が満たされなかったときに、別の処理をしたい場合はv-else
というディレクティブを使うことができます。
v-else
はv-if
を指定した要素と連続で使う必要があります。ここでは、ToDoが1件もない場合に「※ ToDoを追加してください」というメッセージを表示するようにしましょう。次のように追加します。
<ul v-if="todos.length > 0">
...
</ul>
<p v-else>※ ToDoを追加してください</p>
Copy
これにより、ToDoが一件もない場合はメッセージが表示されるようになりました。

ToDoを入れると、メッセージが消えて代わりにリストが表示されます。

v-ifと似たv-show
なお、v-if
と似た動きをするディレクティブとしてv-show
というものがあります。こちらは、要素自体は削除せずにCSSのdisplay
プロパティで表示を制御するためのものです。特別な理由がなければ、v-if
を使っておいた方が良いでしょう。
以下執筆中

