Vue.js3でTODOリストを実装③
勉強の備忘録として記事を書いてます。
Vue.jsでTODOリストを開発していきます。Geminiでコード生成して、不明点や疑問点はchatGPTを頼り、補足してもらうような形で開発を進めました。
アウトプットして自分の中の知識を固めたいという思いで書いていますが、誰かのために役に立てれば嬉しいです。
今回は「追加したタスクを全て・完了・未完了に分類する」子コンポーネントTodoIFilter.vueのコードをまとめていきます。
🐔 親コンポーネント(App.vue)
<template>
<TodoFilter
:current-filter="filter"
@set-filter="filter = $event" />
</template>
@set-filter="filter = $event"
子から送られてくるset-filterイベントを受け取り親のfilterを更新。$eventには子からemitされた値'all','active','completed'がはいる。
🐤 子コンポーネント(TodoFilter.vue)
<script setup>
defineProps({
currentFilter: {
type: String,
required: true
}
});
const emit = defineEmits(['set-filter']);
</script>
defineProps({});で親から情報を受け取る(Props)ための定義
currentFilter:{}
親の:current-filter="filter"が渡る部分。キャメルケースに変換するのを忘れない!ここには親のfilterの値が入る。
親のfilterの値はref('all');でリアクティブな変数にしてるため、filter.valueが子コンポーネントのcurrentFilterに渡ることで、子側はcurrentFilterを参照すれば今どのフィルターが選択されているかがわかる。なので、親側でfilter.value = 'active'に変わると、子のcurrentFilterも自動的に'active'になる。
{type: String, required: true}については、Vueの警告を避けるために予め中身を宣言しておく。親からもらったこのpropsは文字列であるべきことを伝えるtype: Stringと、親が必ずこのpropsを渡す必要があることを宣言するためのrequired: true 必須ではないがpropsするときは宣言しておいた方が安心。
親から定義されてる@set-filterイベントを子コンポーネントにemitする。親側は、@set-filter="filter = $event"で受け取って、filterを更新する。
<template>
<div>
<button
@click="emit('set-filter', 'all')"
:class="{ active: currentFilter === 'all' }">
全て
</button>
<button
@click="emit('set-filter', 'active')"
:class="{ active: currentFilter === 'active' }">
未完了
</button>
<button
@click="emit('set-filter', 'completed')"
:class="{ active: currentFilter === 'completed' }">
完了
</button>
</div>
</template>
emit('set-filter', 'all')は、子から親にイベントを送る仕組み。@clickでボタンがクリックされたときにemitが発火。
'set-filter'という名前のイベントを親の@set-filterに送る。
そしたら値'all'が一緒に渡される。その値が親の$eventに渡る。
そうすると親が@set-filter="filter = $event"で受け取るのでfilterを'all','active','completed'に更新する。
:class="{ active: currentFilter === 'all' }"
:classは動的にクラスを付与するためのVueの機能。{ active: 条件}の形で使うと条件がtrueのときだけactiveクラスが付与される。currentFilterは親から渡されるpropsで、現在選択中のフィルターの値を持っているので、値が'all'の場合「全て」ボタンにactiveクラスが付与される。
現在選択中のフィルターに対してわかりやすく背景色や文字色を変更したい場合は、element.activeにスタイリングすると適用される。
Discussion