サンプルイメージ
作りかけですが、備忘録としてNuxt3を使ったアプリを作ってみます。
どういったものかといいますと、下記の画面から登録するタスク名を入力します。
inputタグ
のすぐ下にチェックボックス(TrueまたはFalse)をチェックを入れるとデータベースPostgreSQLに登録されます。
①タスク一覧画面
また、前述の位置ら㎜画面のID列のボタンをクリックすると、こちら②の詳細画面に遷移して陸得るとパラメータからID値を画面に表示するというものです。
使用する技術スタック
ソフトウェア |
---|
Nuxt3 |
TypeScriot |
TailwindCSS |
Prisma |
PostgreSQL |
ディレクトリ構造
プロジェクト名
├── pages/
│ ├── index.vue
│ └── detail.vue
├── server/
│ └── api/
│ ├── create.ts
│ └── task.ts
└── prisma/
├── migrate
└── schema.prisma
アプリ作成前の準備
今回、Nuxt3とデータベースを接続するために使うORMマッパーは、Prismaを使います。
こちらをプロジェクト直下のコマンド画面でインストールしておきましょう。
タスクの情報をデータベースに入れるので、PostgreSQLの接続情報を入れましょう。
DATABASE_URL="postgresql://(ユーザー名):(パスワード)@localhost:5432/(データベース名)"
今回使用するために更新したデータベース情報はこちら↓
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/nuxtdb"
スキーマ定義を作成する
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Task {
id Int @id @default(autoincrement())
task String
completed Boolean
created_at DateTime @default(now())
}
(フロント側)一覧画面の作成
さて、準備が整ったのでまずは一覧画面を作ってみます。
タスク名が空文字を入力した場合は、登録しない処理も追加しておきました。
// 空のタスクは送信しない
if (!task.value) {
//警告メッセージを表示する
taskErrorWarning.value = 'タスク名を入力してください。';
return
};
//以降の処理は省略
全体のコードはこちら↓
<script setup lang="ts">
import { ref } from 'vue';
// 新しいタスクを保持するローカル変数
const task = ref('');
//エラーメッセージをref定義する
const taskErrorWarning = ref('');
//チェックボックスをref定義する
const checked = ref(false);
// 全タスクを取得する
const { data: tasks } = useFetch('/api/task');
const handleCreateData = async (e: Event) => {
// フォーム送信によるページリロードを防ぐ
e.preventDefault();
//警告メッセージを削除する
taskErrorWarning.value = '';
// 空のタスクは送信しない
if (!task.value) {
//警告メッセージを表示する
taskErrorWarning.value = 'タスク名を入力してください。';
return
};
const newTask = await useFetch('/api/create', {
method: 'POST',
body: {
task: task.value,
checked:checked.value,
},
});
if(!newTask){
//データベース登録失敗の場合
let failValue = document.getElementById('failMag');
failValue.innerHTML= '登録に失敗しました。';
return;
}
let successValue = document.getElementById('successMag');
successValue.innerHTML = '登録に成功しました。';
console.log(task.value);
};
</script>
<template>
<div class="flex items-center justify-center min-h-screen bg-gray-100">
<div>
<span id="successMag" class="h-14"></span>
<span id="failMag" class="h-14"></span>
</div>
<div class="w-full max-w-sm p-6 bg-white rounded-lg shadow-md">
<h1>タスク登録</h1>
<form @submit.prevent="handleCreateData">
<div>
<input v-model="task" class="shadow apperrance-none border rounded" placeholder="タスクを入力" maxlength="10"/>
<div class="inpurWarningArea">
<span v-if="taskErrorWarning" class="label text-warning text-red-500">{{taskErrorWarning}}</span>
</div>
</div>
<div>
<input type="checkbox" v-model="checked"/>
</div>
<div class="flex items-center justify-between">
<button type="submit" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
タスクを登録
</button>
</div>
</form>
</div>
<table class="table-auto">
<thead>
<tr>
<th scope="col" class="border border-black px-4 py-4">ID</th>
<th scope="col" class="border border-black px-4 py-4">タスク</th>
<th scope="col" class="border border-black px-4 py-4">進捗</th>
<th scope="col" class="border border-black px-4 py-4">更新日時</th>
</tr>
</thead>
<tbody>
<tr v-for="task in tasks" :key="task.id">
<td class="border border-black px-4 py-4">
<a :href="`/detail?id=${task.id}`" class="bg-green-500 text-white font-bold py-2 px-4 rounded">{{task.id}}</a>
</td>
<td class="border border-black px-4 py-4">{{task.task}}</td>
<td class="border border-black px-4 py-4">
<span v-if="task.completed == true" class="bg-blue-500 text-white font-bold py-2 px-4 rounded">完了</span>
<span v-if="task.completed == false" class="bg-red-500 text-white font-bold py-2 px-4 rounded">まだ</span>
</td>
<td class="border border-black px-4 py-4">{{task.created_at}}</td>
</tr>
</tbody>
</table>
</div>
</template>
つぎに、詳細画面です(作りかけです...)
一覧画面のID列をクリックしてリクエストパラメータにIDを付与します。
そのID値をvue-routerコンポーネント
で受け取って画面に表示します。
Nuxt3では、vue-routerコンポーネント
は標準でついているのでパッケージ管理ツールyarn
やnpm
でのインストールは不要です。
<script setup lang="ts">
import {useRoute} from 'vue-router'
// 現在のルート情報を取得
const route = useRoute();
// クエリパラメータからidを取得
const taskId = route.query.id;
</script>
<template>
<div>
<h1>タスクの詳細ページ</h1>
<h2>タスクのID値は、{{taskId}}</h2>
</div>
</template>
サーバ側の作成
データベース登録するためのコード↓
import { PrismaClient } from "@prisma/client"
const prisma = new PrismaClient()
export default defineEventHandler(async (event) => {
const body = await readBody(event);
//データベース登録完了フラグを用意する
let flag:boolean = false;
try{
const newTask = await prisma.task.create({
data: {
task: body.task,
completed: body.checked,//boolean値
}
});
flag = true;
return flag;
}catch(error){
return flag;
}
})
データベースからレコードを取得するためのコード↓
import { PrismaClient } from "@prisma/client";
export default defineEventHandler(async(event)=>{
const prisma = new PrismaClient();
if(event.node.req.method === 'GET'){
const tasks = await prisma.task.findMany();
return tasks;
}
if(event.node.req.method === 'POST'){
const body = await readBody(event);
const newTask = await prisma.task.findMany({
select:{
id:true,
task:true,
completed:true
},
orderBy:{
id:'asc'
}
})
console.log("セレクトしたタスクは、" + newTask);
return newTask;
}
});
以上です。