前回つくった投票アプリの投票機能の部分を vueuse
ライブラリの useCounter
に置き換えてみます。
VueUseはVue向けのユーティリティ集で、便利なComposableが豊富。
変更後のコード
pages/index.vue
<script setup lang="ts">
import { useCounter } from '@vueuse/core'
const { count: remainPoints, dec } = useCounter(10, { min: 0 })
const people = [
'林修(予備校講師)',
'池上彰(ジャーナリスト)',
'松岡修造(元プロテニス選手)',
'樹木希林(女優)',
'北野武(映画監督・タレント)',
'堀江貴文(実業家)',
'羽生結弦(フィギュアスケーター)',
'村上春樹(作家)',
'大谷翔平(プロ野球選手)',
'天海祐希(女優)']
</script>
<template>
<div>
<h1>投票画面</h1>
<h2>先生になってほしい有名人は?</h2>
<div>
のこりポイント
<span class="point">
{{ remainPoints }}
</span>
</div>
<div v-for="name of people">
<Item :name="name" :disabled="remainPoints === 0" @update="dec" />
</div>
</div>
</template>
<style lang="css">
.point {
font-size: x-large;
}
</style>
components/Item.vue
<script setup lang="ts">
import { useCounter } from '@vueuse/core'
const { count: point, inc } = useCounter(0, { min: 0 })
const props = defineProps<{
name: string
disabled: boolean
}>()
const emit = defineEmits(['update']);
function handleClick() {
inc()
emit('update')
}
</script>
<template>
<div class="card">
<div>
{{ props.name }}
</div>
<div class="right">
<button @click="handleClick" :disabled="props.disabled">
投票する
</button>
<div class="point">
{{ point }}
</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;
}
</style>
変更点
-
@vueuse/core
のインストール -
useCounter
の適用 -
Item.vue
への切り出し - リファクタリング(
type Item
の廃止、defineEmits
による子→親へのイベント伝播)
差分の詳細はこちら