Nuxt4のキャッチアップもかねて、単純な投票機能をもったアプリをつくってみたい。
※結果だけ先に書くと、このアプリではNuxt4の新機能にはたどりつけていません ディレクトリが app
に集約されたのは、今更感はあれどみやすくスッキリしてよいと感じた。
仕様
- ひとり10ポイントもっている
- 投票は1人に10ポイントいれてもいいし、10人に1ポイントずついれてもいい
- 各投票のポイントをリアルタイムに表示する
レポジトリ作成
パッケージマネージャは前から気になっていたbunをつかうことにする。
> npx nuxi init nuxt-poll
✔ Which package manager would you like to use?
bun
◐ Installing dependencies...
bun install v1.1.34 (5e5e7c60)
$ nuxt prepare
✔ Types generated in .nuxt
+ nuxt@3.14.1592
+ vue@3.5.13
+ vue-router@4.5.0
609 packages installed [21.13s]
Nuxt4のディレクトリ構造に設定
まだNuxt4は正式リリースされていないので、nuxt@3.14.1592
を起点にNuxt4用の設定が必要。
- compatibilityVersionを4にする
- appディレクトリを作成し、その配下にディレクトリを作るようにする
nuxt.config.ts
export default defineNuxtConfig({
future: {
compatibilityVersion: 4,
},
})
app配下に配置するディレクトリ
- assets
- components
- composables
- layouts
- middleware
- pages
- plugins
トップページ作成
app/pages/index.vue
<script setup lang="ts">
</script>
<template>
<div>
<h1>投票画面</h1>
</div>
</template>
確認
> bun dev
投票アイテムの表示
pages/poll.vue
<script setup lang="ts">
type Item = {
name: string
}
const people: Item[] = [
{ name: '林修(予備校講師)' },
{ name: '池上彰(ジャーナリスト)' },
{ name: '松岡修造(元プロテニス選手)' },
{ name: '樹木希林(女優)' },
{ name: '北野武(映画監督・タレント)' },
{ name: '堀江貴文(実業家)' },
{ name: '羽生結弦(フィギュアスケーター)' },
{ name: '村上春樹(作家)' },
{ name: '大谷翔平(プロ野球選手)' },
{ name: '天海祐希(女優)' }]
</script>
<template>
<div>
<h1>投票画面</h1>
<h2>先生になってほしい有名人は?</h2>
<div>
のこりポイント
10
</div>
<div v-for="item of people">
<div class="card">
<div>
{{ item.name }}
</div>
<div class="right">
<button>
投票する
</button>
<div class="point">
0
</div>
</div>
</div>
</div>
</div>
</template>
<style lang="css">
.card {
padding: 1rem 0.5rem;
margin: 0.5rem;
border: 1px solid #333;
border-radius: 5px;
display: flex;
justify-content: space-between;
}
.right {
display: flex;
gap: 30px;
align-items: center;
margin-right: 2rem;
}
.point {
font-size: x-large;
}
</style>
投票するの実装(投票数の増加)
type Item = {
name: string,
points: number
}
// Item[] → ref(Item[]) の配列にする
const people = ref([
{
name: '林修(予備校講師)',
points: 0
},
// ... おなじように points: 0 を書いていく
])
// 投票の実装
// 渡されたitemの投票数をカウントアップ
const clickPoll = (item: Item) => {
item.points += 1
}
<button @click="clickPoll(item)">
投票する
</button>
<div class="point">
{{ item.points }} // 現在の投票数を表示
</div>
持ち点の増減の実装
<div>
のこりポイント
<span class="point">
{{ remainPoints }}
</span>
</div>
const remainPoints = ref(10)
const clickPoll = (item: Item) => {
--remainPoints.value
item.points += 1
}
10ポイント使ったら投票無効にする
<button @click="clickPoll(item)" :disabled="remainPoints === 0">
投票する
</button>