L08 ch03 — v-for で リスト描画
テクノロジ系 / L08 vue-basic — Vue 3 入門
L08 ch03 — v-for で リスト描画
配列を反復して DOM 要素を量産
ゴール
v-for="item in items"構文:keyの重要性- 配列メソッド (push) で動的更新
基本
<script setup>
import { ref } from 'vue'
const fruits = ref(['りんご', 'みかん', 'ぶどう'])
</script>
<template>
<ul>
<li v-for="fruit in fruits" :key="fruit">
{{ fruit }}
</li>
</ul>
</template>オブジェクトのリスト
<script setup>
const tasks = ref([
{ id: 1, title: '買い物' },
{ id: 2, title: '掃除' },
])
</script>
<template>
<ul>
<li v-for="task in tasks" :key="task.id">
{{ task.title }}
</li>
</ul>
</template>key 属性の重要性
<!-- ❌ index を key にすると並び替えで DOM 混乱 --> <li v-for="(item, i) in items" :key="i"> <!-- ✅ ユニーク ID を key に --> <li v-for="item in items" :key="item.id">
→ Vue は key で要素を識別、再利用する
動的追加
<script setup>
const tasks = ref([])
const newTitle = ref('')
function addTask() {
if (!newTitle.value.trim()) return
tasks.value.push({
id: Date.now(),
title: newTitle.value,
})
newTitle.value = ''
}
</script>
<template>
<input v-model="newTitle" />
<button @click="addTask">追加</button>
<ul>
<li v-for="t in tasks" :key="t.id">{{ t.title }}</li>
</ul>
</template>index 付き
<li v-for="(item, index) in items" :key="item.id">
{{ index + 1 }}: {{ item.title }}
</li>罠: v-for と v-if 同一要素
<!-- ❌ Vue 3 では if が外側評価 → 意図と違う動作 -->
<li v-for="t in tasks" v-if="t.done">...
<!-- ✅ template で分離 -->
<template v-for="t in tasks" :key="t.id">
<li v-if="t.done">{{ t.title }}</li>
</template>drill
drill/ — fill-vfor
ハンズオン
ch03-v-for 演習ガイド
受講生向け演習問題集
採点の仕組み (読んでから始めてください)
採点テストは 「お題の通りに動くか」 を機械的にチェックします。
ドリルごとに 3つのタイプ があるので、各ドリル冒頭の 【タイプ】 を確認してください。
タイプ fill (穴埋め問題) — 文法・APIを知っているか
___(3個並んだアンダースコア) の空欄を埋める- 既存の
<template>のテキストやボタン順は そのまま - ロジック自由度: 低 (お題どおりに直す)
タイプ add (機能追加問題) — 既存コードに機能を足せるか
- 既存コードを残したまま、新しい機能を 追加 する
- 実装方法は自由 (関数名・変数名・内部ロジックは好きに)
- ただしテストが要求する見た目 (表示テキスト・ボタンの並び順) は守る
- 既存テストを壊さないこと
タイプ build (ゼロベース実装問題) — 仕様から実装を組み立てられるか
- ほぼ空の
App.vueから 自力で全部書く <template>構造・id/class・内部ロジック: 完全に自由- 守るのは画面の機能仕様だけ: 表示するテキスト・ボタンの操作で何が起きるか
- 一番ハードだが、実装力が一番つくタイプ
3タイプ共通で守ること
- ファイル名 (
App.vue) は変えない tests/フォルダは触らない (採点ロジック)- テンプレートの 表示テキスト (「カウント:」等) はテストが見ているので残す
このガイドのドリル一覧
| # | ドリル名 | タイトル | タイプ | 難易度 |
|---|---|---|---|---|
| 1 | 01-fill-vfor | v-for + :key - 配列のループレンダリング | 🔧 穴埋め | ★ |
> 詰まったら ヒント ページを開く。それでも分からなければ講師に質問。
ドリル 1: v-for + :key - 配列のループレンダリング
ドリル名: 01-fill-vfor
> 🔧 【タイプ: 穴埋め問題】 ___ の部分を埋めて完成させてください。既存のコード構造は変えないこと。
問題
___ を埋めて、入力したタスクをリストに追加するアプリを完成させよ。___ は全部で4箇所ある。
<script setup>
import { ref } from 'vue'
const newTitle = ref('')
const tasks = ref([])
function addTask() {
if (!newTitle.value.trim()) return
tasks.value.push({ title: newTitle.value })
newTitle.value = ''
}
</script>
<template>
<input ___="newTitle" placeholder="タスク名を入力" /> <!-- ___1: 入力値とデータを双方向に繋ぐディレクティブ -->
<button @click="addTask">追加</button>
<ul>
<li ___ ="task in tasks" :key="task.title"> <!-- ___2: 配列を繰り返すディレクティブ -->
{{ ___ }} <!-- ___3: タスクのタイトルを表示 -->
</li>
</ul>
<p>{{ tasks.___ }} 件</p> <!-- ___4: 配列の要素数を返すプロパティ -->
</template>確認方法
- タスク名を入力して「追加」をクリックするとリストに追加される
- 件数が増える
- 空文字では追加されない
ドリル 1: ヒント
ドリル名: 01-fill-vfor
> ⚠️ 自力で考えてから読んでください
___1: 入力欄とデータを「双方向」に繋ぐ Vue ディレクティブ。v-???___2: 配列をループして各要素をliとして表示するディレクティブ。v-???___3:taskオブジェクトのtitleプロパティ___4: JavaScript 配列の要素数を返す標準プロパティ
考えてみよう
既定では正解・不正解の判定はしません。自分のペースで「答えを見る」を。採点してほしい場合だけ「採点してほしい」を押してください。
ch03-v-for 演習ガイド
受講生向け演習問題集
採点の仕組み (読んでから始めてください)
採点テストは 「お題の通りに動くか」 を機械的にチェックします。
ドリルごとに 3つのタイプ があるので、各ドリル冒頭の 【タイプ】 を確認してください。
タイプ fill (穴埋め問題) — 文法・APIを知っているか
___(3個並んだアンダースコア) の空欄を埋める- 既存の
<template>のテキストやボタン順は そのまま - ロジック自由度: 低 (お題どおりに直す)
タイプ add (機能追加問題) — 既存コードに機能を足せるか
- 既存コードを残したまま、新しい機能を 追加 する
- 実装方法は自由 (関数名・変数名・内部ロジックは好きに)
- ただしテストが要求する見た目 (表示テキスト・ボタンの並び順) は守る
- 既存テストを壊さないこと
タイプ build (ゼロベース実装問題) — 仕様から実装を組み立てられるか
- ほぼ空の
App.vueから 自力で全部書く <template>構造・id/class・内部ロジック: 完全に自由- 守るのは画面の機能仕様だけ: 表示するテキスト・ボタンの操作で何が起きるか
- 一番ハードだが、実装力が一番つくタイプ
3タイプ共通で守ること
- ファイル名 (
App.vue) は変えない tests/フォルダは触らない (採点ロジック)- テンプレートの 表示テキスト (「カウント:」等) はテストが見ているので残す
このガイドのドリル一覧
| # | ドリル名 | タイトル | タイプ | 難易度 |
|---|---|---|---|---|
| 1 | 01-fill-vfor | v-for + :key - 配列のループレンダリング | 🔧 穴埋め | ★ |
> 詰まったら ヒント ページを開く。それでも分からなければ講師に質問。
ドリル 1: v-for + :key - 配列のループレンダリング
ドリル名: 01-fill-vfor
> 🔧 【タイプ: 穴埋め問題】 ___ の部分を埋めて完成させてください。既存のコード構造は変えないこと。
問題
___ を埋めて、入力したタスクをリストに追加するアプリを完成させよ。___ は全部で4箇所ある。
<script setup>
import { ref } from 'vue'
const newTitle = ref('')
const tasks = ref([])
function addTask() {
if (!newTitle.value.trim()) return
tasks.value.push({ title: newTitle.value })
newTitle.value = ''
}
</script>
<template>
<input ___="newTitle" placeholder="タスク名を入力" /> <!-- ___1: 入力値とデータを双方向に繋ぐディレクティブ -->
<button @click="addTask">追加</button>
<ul>
<li ___ ="task in tasks" :key="task.title"> <!-- ___2: 配列を繰り返すディレクティブ -->
{{ ___ }} <!-- ___3: タスクのタイトルを表示 -->
</li>
</ul>
<p>{{ tasks.___ }} 件</p> <!-- ___4: 配列の要素数を返すプロパティ -->
</template>確認方法
- タスク名を入力して「追加」をクリックするとリストに追加される
- 件数が増える
- 空文字では追加されない
ドリル 1: ヒント
ドリル名: 01-fill-vfor
> ⚠️ 自力で考えてから読んでください
___1: 入力欄とデータを「双方向」に繋ぐ Vue ディレクティブ。v-???___2: 配列をループして各要素をliとして表示するディレクティブ。v-???___3:taskオブジェクトのtitleプロパティ___4: JavaScript 配列の要素数を返す標準プロパティ
ch03-v-for 演習解説
⚠️ 自力でドリルを解いてから読んでください
ドリル 1: v-for + :key - 配列のループレンダリング — 模範解答
ドリル名: 01-fill-vfor
<script setup>
import { ref } from 'vue'
const newTitle = ref('')
const tasks = ref([])
function addTask() {
if (!newTitle.value.trim()) return
tasks.value.push({ title: newTitle.value })
newTitle.value = ''
}
</script>
<template>
<input v-model="newTitle" placeholder="タスク名を入力" />
<button @click="addTask">追加</button>
<ul>
<li v-for="task in tasks" :key="task.title">
{{ task.title }}
</li>
</ul>
<p>{{ tasks.length }} 件</p>
</template>ドリル 1: v-for + :key - 配列のループレンダリング — 解説
ドリル名: 01-fill-vfor
<script setup>
import { ref } from 'vue'
const newTitle = ref('')
const tasks = ref([])
function addTask() {
if (!newTitle.value.trim()) return
tasks.value.push({ title: newTitle.value })
newTitle.value = ''
}
</script>
<template>
<input v-model="newTitle" placeholder="タスク名を入力" />
<button @click="addTask">追加</button>
<ul>
<li v-for="task in tasks" :key="task.title">
{{ task.title }}
</li>
</ul>
<p>{{ tasks.length }} 件</p>
</template>___1→v-model___2→v-for___3→task.title___4→length
Q: v-for と v-model の空欄を埋める
問題
___ を埋めて、入力したタスクをリストに追加するアプリを完成させよ。___ は全部で4箇所ある。
<script setup>
import { ref } from 'vue'
const newTitle = ref('')
const tasks = ref([])
function addTask() {
if (!newTitle.value.trim()) return
tasks.value.push({ title: newTitle.value })
newTitle.value = ''
}
</script>
<template>
<input ___="newTitle" placeholder="タスク名を入力" /> <!-- ___1: 入力値とデータを双方向に繋ぐディレクティブ -->
<button @click="addTask">追加</button>
<ul>
<li ___ ="task in tasks" :key="task.title"> <!-- ___2: 配列を繰り返すディレクティブ -->
{{ ___ }} <!-- ___3: タスクのタイトルを表示 -->
</li>
</ul>
<p>{{ tasks.___ }} 件</p> <!-- ___4: 配列の要素数を返すプロパティ -->
</template>確認方法
- タスク名を入力して「追加」をクリックするとリストに追加される
- 件数が増える
- 空文字では追加されない
ヒント: v-for と v-model の空欄
___1: 入力欄とデータを「双方向」に繋ぐ Vue ディレクティブ。v-???___2: 配列をループして各要素をliとして表示するディレクティブ。v-???___3:taskオブジェクトのtitleプロパティ___4: JavaScript 配列の要素数を返す標準プロパティ
解答: v-for と v-model の空欄
<script setup>
import { ref } from 'vue'
const newTitle = ref('')
const tasks = ref([])
function addTask() {
if (!newTitle.value.trim()) return
tasks.value.push({ title: newTitle.value })
newTitle.value = ''
}
</script>
<template>
<input v-model="newTitle" placeholder="タスク名を入力" />
<button @click="addTask">追加</button>
<ul>
<li v-for="task in tasks" :key="task.title">
{{ task.title }}
</li>
</ul>
<p>{{ tasks.length }} 件</p>
</template>___1→v-model___2→v-for___3→task.title___4→length