こんにちは。
アイレットデザイン事業部、フロントエンドエンジニアの辻と申します。
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をある程度理解していれば、ここまでの内容はそんなに難しくないと感じました。
まだまだ機能はあるので、継続して学習していきます。