コンポーネント化
Vueではパーツごとにコンポーネントを細かく分ける。
Item.vue
<script setup lang="ts">
import { ref } from 'vue'
import ItemPostForm from './ItemPostForm.vue';
import ItemList from './ItemList.vue';
const items = ref([{ id: 0, name: "ポーション", price: 100 }, { id: 2, name: "ハイポーション", price: 200 }])
const postItem = (name: string, price: number) => {
const item = { id: Math.random(), name, price };
items.value.push(item);
inputtingName.value = "";
inputtingPrice.value = 0;
}
const deleteItem = (id: number) => {
items.value = items.value.filter(t => t.id != id)
}
</script>
<template>
<div class="container">
<h1>アイテム屋</h1>
<ItemPostForm @post-item="postItem"/>
<div class="item-container">
<p v-if="items.length <= 0">Sold Out</p>
<ul v-else>
<ItemList :items="items" @delete-item="deleteItem"/>
</ul>
</div>
</div>
</template>
ItemList.vue
<script setup lang="ts">
import { defineProps } from 'vue';
type Item = {
id: number,
name: string,
price: number,
}
type Props = {
items: Item[]
}
// Propsとして受け取る
// 基本的に子コンポーネントでは値を変更しない
defineProps<Props>()
const emit = defineEmits(['delete-item'])
const deleteItem = (id: number) => {
emit('delete-item', id)
}
</script>
<template>
<li v-for="item in items" :key="item.id" class="item-list">
<span>{{ item.name }} {{ item.price }}</span>
<button class="delete-button" @click="deleteItem(item.id)">delete</button>
</li>
</template>
ItemPostForm.vue
<script setup lang="ts">
import { ref, defineEmits } from 'vue'
const inputtingName = ref<string>("");
const inputtingPrice = ref<number>(0);
// 子から親へのイベント伝播
const emit = defineEmits(['post-item'])
const postItem = () => {
emit('post-item', inputtingName.value, inputtingPrice.value)
}
</script>
<template>
<div class="form-container">
<input v-model="inputtingName"/>
<input v-model="inputtingPrice"/>
<button class="save-button" @click="postItem()">post</button>
</div>
</template>
親コンポーネントから子コンポーネントへの伝播 Props
Item.vue
<script setup lang="ts">
import { ref } from 'vue'
import ItemList from './ItemList.vue';const items = ref([{ id: 0, name: "ポーション", price: 100 }, { id: 2, name: "ハイポーション", price: 200 }])
</script>
<template>
<div class="container">
<h1>アイテム屋</h1>
<ItemPostForm"/>
<div class="item-container">
<p v-if="items.length <= 0">Sold Out</p>
<ul v-else>
<!-- v-bindで値を渡す。v-bindは省略できる。
v-bind:itemsと同じ -->
<ItemList :items="items"/>
</ul>
</div>
</div>
</template>
ItemList.vue
<script setup lang="ts">
import { defineProps } from 'vue';
type Item = {
id: number,
name: string,
price: number,
}
// Propsを定義
type Props = {
items: Item[]
}
// Propsとして受け取る
// 基本的に子コンポーネントでは値を変更しない
defineProps<Props>()
</script>
子コンポーネントから親コンポーネントへの伝播 Emit
VueではEmitで伝播させる。
v-bindも利用可能だが非推奨。
Item.vue
<script setup lang="ts">
import { ref } from 'vue'
import ItemPostForm from './ItemPostForm.vue';
import ItemList from './ItemList.vue';
const items = ref([{ id: 0, name: "ポーション", price: 100 }, { id: 2, name: "ハイポーション", price: 200 }])
// javascriptではkeyと引数の値が同じであれば両略できる
// name:name, price:priceに同じ
const postItem = (name: string, price: number) => {
const item = { id: Math.random(), name, price };
items.value.push(item);
inputtingName.value = "";
inputtingPrice.value = 0;
}
const deleteItem = (id: number) => {
items.value = items.value.filter(t => t.id !== id)
}
</script>
<template>
<div class="container">
<h1>アイテム屋</h1>
<!-- postItem関数に伝播させる -->
<ItemPostForm @post-item="postItem"/>
<div class="item-container">
<p v-if="items.length <= 0">Sold Out</p>
<ul v-else>
<!-- deleteItem関数に伝播させる -->
<ItemList :items="items" @delete-item="deleteItem"/>
</ul>
</div>
</div>
</template>
ItemPostForm.vue
<script setup lang="ts">
import { ref, defineEmits } from 'vue'
const inputtingName = ref<string>("");
const inputtingPrice = ref<number>(0);
// emitでイベント伝播
// 大文字は小文字に変換し、ハイフンを付ける
// postItem -> post-item
const emit = defineEmits(['post-item'])
const postItem = () => {
emit('post-item', inputtingName.value, inputtingPrice.value)
}
</script>
ItemList.vue
<script setup lang="ts">
import { defineProps } from 'vue';
type Item = {
id: number,
name: string,
price: number,
}
type Props = {
items: Item[]
}
defineProps<Props>()
// emitでイベント伝播
// 大文字は小文字に変換し、ハイフンを付ける
// deleteItem -> delete-item
const emit = defineEmits(['delete-item'])
const deleteItem = (id: number) => {
emit('delete-item', id)
}
</script>
参考