はじめに
勉強も兼ねて、今回は買い物メモのアプリを作成することにしました。
もともと忘れっぽい性格なので、よく何を買うんだっけ、、、?
スーパーに行ってから考えるタイプなので、自作アプリで乗り越えられたらベストかなと。
シンプルに見やすく、継続して利用できそうなアプリにしたいと思います。
要件定義
想定場面
買い物に行く際、アプリを使用し、購入タスクをつける。
機能
リストへの追記・修正・削除
カテゴリ分け(食品・日用品など、自分で追加・編集可能)
検索機能
技術選定
フロントエンド:vue.js
バックエンド:python、flask
開発環境:VsCode
学習内容(~開発環境作成)
git
git init #gitを始めるおまじない
.gitignoreファイルの作成
node_modules/ #node_modules フォルダを無視
*.log #ログファイルを無視
.env #環境設定ファイルを無視
flask
・Pythonで書かれたフレームワークのこと
・最小限のコア機能やプラグイン、拡張モジュールを搭載し、必要な機能のみを追加できる
・シンプルで使いやすく、初心者向けのフレームワーク→覚えることが少ない
Node.js
・javascriptのサーバー側実行環境
node -v #インストールされているかのチェック
vue.js インストール時の選択項目
・typescript:(よくわかりませんでした)
・JSX support:JSX(javascript XML)→javascript内にHTMLなど別言語を組み込むかどうか
・vue Router:SPA(single page app)にするかどうかで使用、ページ移動をするかのようにURLを書き換える機能がある
・Pinia:公式状態管理アプリ
・Vitest:(よくわかりませんでした)
・EsLint:誤った構文のチェックをしてくれる
・Prettier:javascriptの自動フォーマッターで、インデント修正などをしてくれる
→今回はEsLint、Prettierのみ採用
npm
npm=Node Package Manager
pnpm=performance NPM(javascriptのパッケージ管理ツール)
npm sreate vue@latest #Vueプロジェクトの作成
npm install #パッケージのインストール
npm run dev #開発サーバーを起動
コードの中身
<template>
<div class="flex flex-col min-h-screen">
<!-- ✅ ヘッダー -->
<header class="bg-green-200 text-gray-800 p-4 flex justify-between items-center">
<div class="flex items-center space-x-2">
<span class="text-xl">🛒</span>
<h1 class="text-xl font-bold">Shopping-ListApp</h1>
</div>
<div>{{ currentDate }}</div>
</header>
<!-- ✅ 本体は左右2カラム -->
<div class="flex flex-1">
<!-- 左サイドバー -->
<aside class="w-48 bg-gray-800 text-white p-4 space-y-4">
<button class="w-full bg-gray-700 hover:bg-gray-600 p-2 rounded">Settings</button>
<button class="w-full bg-gray-700 hover:bg-gray-600 p-2 rounded">Search</button>
<button class="w-full bg-gray-700 hover:bg-gray-600 p-2 rounded">Add Item</button>
</aside>
<!-- 右側:フォームとリスト -->
<main class="flex-1 p-6 bg-white">
<!-- フォーム -->
<div class="mb-4">
<input
v-model="newItem.name"
placeholder="商品名"
class="border p-2 mr-2"
/>
<input
v-model.number="newItem.quantity"
type="number"
placeholder="数量"
class="border p-2 mr-2 w-20"
/>
<select v-model="newItem.category" class="border p-2 mr-2">
<option value="Food">Food</option>
<option value="Household">Household</option>
</select>
<button @click="addItem" class="bg-green-500 text-white px-4 py-2 rounded">
追加
</button>
</div>
<!-- リスト -->
<h1 class="text-2xl font-bold mb-4">買い物リスト</h1>
<ul>
<li
v-for="item in items"
:key="item.id"
class="mb-2 p-2 border rounded flex justify-between items-center"
>
<span>🛒 {{ item.name }}({{ item.quantity }})</span>
<button
@click="deleteItem(item.id)"
class="bg-red-500 text-white px-2 py-1 rounded ml-4"
>
🗑 削除
</button>
</li>
</ul>
</main>
</div>
</div>
</template>
<script>
import api from './api'
export default {
data() {
return {
items: [],
newItem: {
name: '',
quantity: 1,
category: 'Food'
},
currentDate: new Date().toLocaleDateString()
}
},
async created() {
const response = await api.getItems()
this.items = response.data
},
methods: {
async addItem() {
if (!this.newItem.name.trim()) return
const response = await api.addItem(this.newItem)
this.items.push(response.data)
this.newItem = { name: '', quantity: 1, category: 'Food' }
},
async deleteItem(id) {
await api.deleteItem(id)
this.items = this.items.filter(item => item.id !== id)
}
}
}
</script>
<style scoped>
/* くすみグリーンの調整やロゴ用 */
.logo {
display: block;
margin: 0 auto 2rem;
}
@media (min-width: 1024px) {
header {
display: flex;
place-items: center;
padding-right: calc(var(--section-gap) / 2);
}
.logo {
margin: 0 2rem 0 0;
}
header .wrapper {
display: flex;
place-items: flex-start;
flex-wrap: wrap;
}
}
</style>
// src/api.js
import axios from 'axios'
const apiClient = axios.create({
baseURL: 'http://localhost:5000', // FlaskのサーバーURL
headers: {
'Content-Type': 'application/json'
}
})
export default {
getItems: () => apiClient.get('/items'),
addItem: (item) => apiClient.post('/items', item),
deleteItem: (id) => apiClient.delete(`/items/${id}`),
// 他の関数はあとで追加
}
from flask import Flask, jsonify, request
from flask_cors import CORS
app = Flask(__name__)
CORS(app) # Vueと通信できるようにする!
# 仮のリストデータ
items = [
{"id": 1, "name": "Apples", "quantity": 5, "category": "Food", "checked": False},
{"id": 2, "name": "Laundry Detergent", "quantity": 1, "category": "Household", "checked": False},
]
@app.route("/items", methods=["GET"])
def get_items():
return jsonify(items)
@app.route("/items", methods=["POST"])
def add_item():
data = request.json
new_item = {
"id": len(items) + 1,
"name": data["name"],
"quantity": data["quantity"],
"category": data["category"],
"checked": False
}
items.append(new_item)
return jsonify(new_item), 201
@app.route("/items/<int:item_id>", methods=["DELETE"])
def delete_item(item_id):
global items
items = [item for item in items if item["id"] != item_id]
return jsonify({"message": "Item deleted"}), 200
if __name__ == "__main__":
app.run(debug=True)
現在のWEBアプリ状況
今後改良すること
・ヘッダーをつけて、横にカートをおしてる女性を白抜きで表示
・日付横に時刻まで入れて今の時間だとタイムセールかも??みたいな風に
・くすみグリーンの色合いで表示をしたいが、まっしろなまま動かず
想定イメージ(chatGPT作成)
おわりに
以前、試しに作ってみたアプリで、なんとなくvueやflaskを利用していましたが、
なぜそのような書き方をするのか、どう修正をすればエラーが解消できるのか等、
今回はかなり細かく調べながら行っています。
今後はデザインをより想定イメージに近づけるように改良を進めていきます。