0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

まっさらな新人研修コーチAdvent Calendar 2024

Day 13

Nuxt4で簡単な投票アプリをつくる

Last updated at Posted at 2024-12-13

Nuxt4のキャッチアップもかねて、単純な投票機能をもったアプリをつくってみたい。
※結果だけ先に書くと、このアプリではNuxt4の新機能にはたどりつけていません :pray: ディレクトリが 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用の設定が必要。

  1. compatibilityVersionを4にする
  2. 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

CleanShot 2024-12-13 at 20.31.47.png

投票アイテムの表示

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>

CleanShot 2024-12-13 at 20.50.09.png

投票するの実装(投票数の増加)

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>

動作イメージ

output.gif

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?