こんにちは。
アイレットデザイン事業部、フロントエンドエンジニアの辻と申します。
Composition APIになり、よりJavaScriptらしく書けるようになったと噂のVue。
チュートリアルを少し触ってみましたので、今回はそちらをまとめてみます。
プロジェクト作成
npm create vue@latest
プロジェクト名などの情報を入力します。
デフォルトでよければ、全てEnterでOKです。
作ったプロジェクトのディレクトリに移動
cd ●●【上で入力したプロジェクト名】
モジュールのインストール
npm install
開発サーバー立ち上げる
npm run dev
これで開発環境ができあがりです。簡単ですね。
これだけだと、開発用ファイルしか存在しないのでサーバーにアップロードする際はビルドが必要です。
ビルドする
npm run build
ディレクトリ構造
・public
画像やCSSなど、外部ファイル群を入れます。
・src
開発フォルダ。開発はこの中のファイルを触っていきます。
ルール
いわゆる、おまじないがいくつかあるので忘れずに記述します。
・scriptタグ
setup属性追加することでComposition APIが使用可能になります。
<script setup>
・・・
</script>
・templateタグ
HTML部分はtemplateタグで囲みます。
・ref
リアクティブな変数を定義する時に使います。
リアクティブとは 値が監視され変更が検知される状態のこと で、値が変更されたときに何かしらの処理のトリガーにする時に使用します。
refで宣言した変数をscript内で扱う場合は、変数名に.valueを付けて参照します。
では、次から実際の記述を見ていきます。
v-text, v-html
テキストやHTMLを表示します。
strongタグを含む文字列の変数を表示してみます。
<script setup> const message = "ようこそ <strong>太郎</strong>さん"; </script> <template> <p v-text="message"></p> <p v-html="message"></p> </template>
結果がこちら。

v-textはstrongタグをテキストとして扱い
v-htmlはstrongタグをHTMLとして扱います。
またv-textは{{ message }}(マスタッシュ構文)で代替が可能です。
<p>{{ message }}</p>
v-bind
属性内に変数を使うときに使用します。
style属性の値に変数を使ってみます。
<script setup>
const message = "ようこそ <strong>太郎</strong>さん";
const color1 = "red";
</script>
<template>
<p v-html="message" v-bind:style="{ backgroundColor: color1, color: 'white' }"></p>
</template>
結果がこちら。

style属性の値に使用したcolor1が反映されています。
またv-bind:は:で省略が可能です。
<p v-html="message" :style="{ backgroundColor: color1, color: 'white' }"></p>
v-model
type="text"のinputに使用し、データとフロント両方で値をバインドします。
inputを使って、双方向バインディングでフロントに表示してみます。
<script setup>
import { ref } from "vue";
const myname = ref("");
</script>
<template>
<p>お名前は?: <input type="text" v-model="myname" /></p>
<p v-html="myname"></p>
</template>
結果がこちら。

inputに入力した内容が反映されています。
v-modelで双方向バインディングされた値を変数内で扱いたい場合は
computedと組み合わせて使用します。
<script setup>
import { ref, computed } from "vue";
const message = computed(() => {
return "ようこそ<strong>" + myname.value + "</strong>さん";
});
const myname = ref("");
</script>
<template>
<p>お名前は?: <input type="text" v-model="myname" /></p>
<p v-html="message"></p>
</template>
結果がこちら。

v-on
イベントをハンドリングします。
簡単なカウンターを作ってみます。
<script setup>
import { ref } from "vue";
const number = ref(0);
const add = () => {
number.value++;
};
const remove = () => {
number.value--;
};
</script>
<template>
<input type="text" v-model="number" />
<button v-on:click="add()">足す</button>
<button v-on:click="remove()">引く</button>
</template>
結果がこちら。

足す引くのイベントをそれぞれハンドリングできました。
またv-on:は@で省略が可能です。
<button @click="add()">足す</button> <button @click="remove()">引く</button>
v-for
配列に基づいて繰り返しレンダリングします。
簡単な配列をフロントに表示してみます。
<script setup>
import { ref } from "vue";
const todos = ref(["掃除", "洗濯", "買い物"]);
</script>
<template>
<ul>
<li v-for="(todo, i) in todos" :key="i">{{ i + 1 }}:{{ todo }}</li>
</ul>
</template>
結果がこちら。

配列項目の掃除、洗濯、買い物を表示できました。
v-if, v-else
条件で表示非表示を切り替えます。
青信号赤信号でテキストが切り替わるボタンを作ってみます。
<script setup>
import { ref } from "vue";
const trafficSignal = ref("blue");
</script>
<template>
<p v-if="trafficSignal === 'blue'">GO!</p>
<p v-else-if="trafficSignal === 'red'">STOP!</p>
<button @click="trafficSignal = 'blue'">青信号</button>
<button @click="trafficSignal = 'red'">赤信号</button>
</template>
結果がこちら。

青信号でGO!が、赤信号でSTOP!が表示できました。
props, slot
コンポーネント間でデータを渡します。
・props
親コンポーネントから子コンポーネントへ値を渡します。
・slot
親コンポーネントから子コンポーネントへテンプレートフラグメントを渡します。
子コンポーネントでデフォルトの値も設定できます。
・AppHeader.vue
<script setup>
defineProps(["textColor"]);
</script>
<template>
<header>
<h1 :style="{ color: textColor }">
<slot>slotデフォルト値</slot>
</h1>
</header>
</template>
・App.vue
<script setup> import AppHeader from "./components/AppHeader.vue"; </script> <template> <AppHeader textColor="red">header</AppHeader> <main>contents</main> </template>
結果がこちら。

親コンポーネント(App.vue)から子コンポーネント(AppHeader.vue)へpropsとslotが渡され
問題なく、反映されました。
ToDoアプリを作ってみる
ここまでの記述を使用してチュートリアルの定番、簡単なToDoアプリを作ってみます。
機能は
- ToDoの登録
- ToDoの削除
<script setup>
import { ref } from "vue";
const todos = ref([]);
const newTodo = ref("");
const addTodo = () => {
todos.value.push(newTodo.value);
newTodo.value = "";
};
const removeTodo = (index) => {
todos.value.splice(index, 1);
};
</script>
<template>
<input type="text" v-model="newTodo" />
<button @click="addTodo()">追加</button>
<ul v-if="todos.length > 0">
<li v-for="(todo, i) in todos" :key="i">
{{ todo }}
<button @click="removeTodo(i)" style="cursor: pointer">x</button>
</li>
</ul>
<p v-else>ToDoを追加してください</p>
</template>
結果がこちら。

部分ごとに解説していきます。
const todos = ref([]);
const newTodo = ref("");
上記は
- ToDoの項目を入れていくための空配列
- 新しいToDoを入れるための空文字列
を宣言しています。
const addTodo = () => {
todos.value.push(newTodo.value);
newTodo.value = "";
};
const removeTodo = (index) => {
todos.value.splice(index, 1);
};
上記は
ToDoを追加、削除する関数を宣言しています。
addTodo()でnewTodoに入力した項目をtodosの配列に追加後、newTodoを空にし
removeTodo()でsplice()で順番を引数に取り、todosから指定の項目を削除します。
<input type="text" v-model="newTodo" /> <button @click="addTodo()">追加</button>
上記は
inputに新しいToDoを入力し、宣言しておいたnewTodoを双方向バインドし
buttonにはaddTodo()をイベントハンドリングしています。
<ul v-if="todos.length > 0">
<li v-for="(todo, i) in todos" :key="i">
{{ todo }}
<button @click="removeTodo(i)" style="cursor: pointer">x</button>
</li>
</ul>
<p v-else>ToDoを追加してください</p>
上記は
todosに情報が入っていればv-forでiを引数にとってリストをレンダリングし
それを使用してremoveTodo()を処理します。
todosに情報がなければToDoを追加してくださいと表示させます。
まとめ
今回は基本的なところを調査してみました。
JavaScriptをある程度理解していれば、ここまでの内容はそんなに難しくないと感じました。
まだまだ機能はあるので、継続して学習していきます。