🗂

# 5.3 Vue の基本書き方(基礎文法編)

に公開

前回は Vite + Vue 3 を使って Hello World を体験した。
ここからはもう少し踏み込み、Vue の基本的な書き方を ToDo リスト を題材に学んでいく。


1. Vue の基本ディレクティブ

Vue では、HTML テンプレートに「ディレクティブ」と呼ばれる属性を付けて制御する。

  • v-for … リストの繰り返し
  • v-if / v-else … 条件分岐
  • v-model … フォーム入力の双方向バインディング
  • @click … イベント(クリック)のバインド

これらを組み合わせると、業務システムでもよく使う 一覧・フォーム・ボタン操作 が簡単に書ける。
たとえば「受注リストを表示する」「チェックボックスで状態を切り替える」などは、これらのディレクティブを組み合わせるだけで実装可能になる。


2. ToDo リスト(素の Vue 実装)

まずは Vue の基本機能だけを使ったシンプルな ToDo リストを作る。

src/views/Todo.vue

<template>
  <div>
    <h2>ToDo リスト</h2>

    <!-- 新規追加フォーム -->
    <input v-model="newTask" placeholder="新しいタスクを入力" />
    <button @click="addTask">追加</button>

    <!-- タスクリスト -->
    <ul>
      <li v-for="(task, index) in tasks" :key="index">
        <span :style="{ textDecoration: task.done ? 'line-through' : 'none' }">
          {{ task.title }}
        </span>
        <button @click="toggleDone(index)">
          {{ task.done ? "未完了に戻す" : "完了にする" }}
        </button>
        <button @click="removeTask(index)">削除</button>
      </li>
    </ul>

    <!-- タスクがないとき -->
    <p v-if="tasks.length === 0">タスクはありません</p>
  </div>
</template>

<script setup>
import { ref } from "vue";

const newTask = ref("");
const tasks = ref([]);

const addTask = () => {
  if (newTask.value.trim() === "") return;
  tasks.value.push({ title: newTask.value, done: false });
  newTask.value = "";
};

const toggleDone = (index) => {
  tasks.value[index].done = !tasks.value[index].done;
};

const removeTask = (index) => {
  tasks.value.splice(index, 1);
};
</script>

解説

  • v-model="newTask" → 入力フォームの値と newTask 変数を常に同期。
  • v-for="(task, index) in tasks" → 配列 tasks をループしてリスト表示。
  • :style="{ textDecoration: task.done ? 'line-through' : 'none' }" → 完了したタスクに打消し線をつける。
  • @click="toggleDone(index)" → ボタンクリックで完了/未完了を切り替える。
  • v-if="tasks.length === 0" → タスクが一件もなければメッセージを表示。

👉 この小さな例だけで Vue の基本文法をほぼ一通り体験できる。


3. Vuetify の導入

素の Vue だけでも動作するが、業務システムでは UI の統一感 が重要。
そのため、UI コンポーネントライブラリの Vuetify を導入する。

なぜ Vuetify を使うのか

  • 業務システムに必要な UI 部品が揃っている
    入力フォーム、一覧テーブル、ダイアログなどを最初から利用可能。

  • Material Design 準拠で統一感がある
    デザイナーがいなくても「それっぽい」見た目になる。

  • 開発効率が高い
    ボタンや入力欄を組み合わせるだけで実用的な画面がすぐ作れる。

  • 素の CSS より保守性が高い
    大規模システムでも UI がバラバラにならない。

👉 Vuetify は「必ず使わなければならない」わけではなく、効率を高めるための道具
もし制約で使えなければ素の CSS でも問題ない。

インストール

npm install vuetify@latest

main.js に Vuetify を追加する。

// src/main.js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import { createPinia } from "pinia";

// Vuetify
import "vuetify/styles";
import { createVuetify } from "vuetify";

import * as components
 from "vuetify/components";

import * as directives
 from "vuetify/directives";

const vuetify = createVuetify({
  components,
  directives,
});

createApp(App).use(router).use(createPinia()).use(vuetify).mount("#app");

解説

  • import "vuetify/styles"; → Vuetify のスタイルを読み込む。
  • createVuetify({ components, directives }) → Vuetify を Vue アプリに登録。
  • .use(vuetify) → これで <v-btn><v-text-field> が使えるようになる。

4. ToDo リスト(Vuetify 版)

同じ機能を Vuetify のコンポーネントで書き直すと、見た目が一気に業務システムっぽくなる。

<template>
  <v-container>
    <h2 class="mb-4">ToDo リスト</h2>

    <!-- 入力フォーム -->
    <v-row>
      <v-col cols="8">
        <v-text-field
          v-model="newTask"
          label="新しいタスク"
          outlined
          dense
        />
      </v-col>
      <v-col cols="4">
        <v-btn color="primary" @click="addTask">追加</v-btn>
      </v-col>
    </v-row>

    <!-- タスク一覧 -->
    <v-list two-line>
      <v-list-item v-for="(task, index) in tasks" :key="index">
        <v-list-item-content>
          <v-list-item-title
            :class="{ 'text-decoration-line-through': task.done }"
          >
            {{ task.title }}
          </v-list-item-title>
        </v-list-item-content>

        <v-list-item-action>
          <v-btn small @click="toggleDone(index)">
            {{ task.done ? "未完了" : "完了" }}
          </v-btn>
          <v-btn small color="error" @click="removeTask(index)">削除</v-btn>
        </v-list-item-action>
      </v-list-item>
    </v-list>

    <!-- タスクがないとき -->
    <v-alert v-if="tasks.length === 0" type="info" dense>
      タスクはありません
    </v-alert>
  </v-container>
</template>

<script setup>
import { ref } from "vue";

const newTask = ref("");
const tasks = ref([]);

const addTask = () => {
  if (newTask.value.trim() === "") return;
  tasks.value.push({ title: newTask.value, done: false });
  newTask.value = "";
};

const toggleDone = (index) => {
  tasks.value[index].done = !tasks.value[index].done;
};

const removeTask = (index) => {
  tasks.value.splice(index, 1);
};
</script>

解説

  • <v-text-field> … Vue の <input> に相当。見た目が整ってラベル付きになる。
  • <v-btn> … ボタン。color="primary" でシステム共通カラーを適用。
  • <v-list> / <v-list-item> … リスト表示用コンポーネント。業務システムでもよく使う。
  • <v-alert> … 情報メッセージを目立つ形で表示。

👉 同じ処理でも Vuetify を使うと 即戦力な UI になる。


💡 AI 活用のポイント

  • 画面デザイン調整は AI が苦手
    Vuetify を使っていても、<v-text-field> とその横の <v-btn> の縦位置がずれるなど、微妙な崩れはよく起こる。

  • AI にコードや画面を見せても一発で直るとは限らない
    「直して」と言っても 1 回で解決しないことが多く、最悪は直らない場合もある。

  • 自力で直す方が早いケースもある
    レイアウト調整に限っては CSS の微修正で済む場合が多いため、自分で調整する力を持っておくと効率的

  • AI を繰り返し使うなら “戦略” が必要
    何度か試して直らない場合は、別のやり方(コンポーネントの入れ替えや配置の変更)を提案させる。
    ただし、既存アプリ全体の整合性が崩れるリスクがあるので注意。

  • 大事なのは整合性の視点
    見た目を直すことだけに集中せず、システム全体の一貫性を保ちながら調整する姿勢が重要。


5. まとめ

  • 素の Vue で基本文法を体験(v-for, v-if, v-model, @click
  • Vuetify を導入して UI をリッチ化(フォーム・リスト・ボタン・アラート)
  • 業務システムでは Vuetify のような UI ライブラリを使うのが前提

👉 次回は axios を使った API 呼び出し に進み、Django REST Framework の API と連携して「一覧画面」を作る。

Discussion