■完成イメージ
■ソースコード
・app.vue(大枠)
app.vue
<script setup lang="ts">
import type { Member } from '@/interfaces';
// 会員情報リストをステートとして用意
useState<Map<number, Member>>(
"memberList",
(): Map<number, Member> => {
const memberListInit = new Map<number, Member>();
memberListInit.set(1, {id: 1, name: "夏目智徹", email: "t@mail.com", points: 89,
note: "入会9か月" });
memberListInit.set(2, {id: 2, name: "チンギスハーン", email: "ttt@mail.com", points: 67,
note: "入会5か月" });
memberListInit.set(3, {id: 3, name: "バモスるい", email: "bbb@mail.com", points: 99,
note: "勧誘中" });
memberListInit.set(4, {id: 4, name: "るい北澤", email: "jjjj@mail.com", points: 20,
note: "" });
memberListInit.set(5, {id: 5, name: "ハリソン山中", email: "hari@mail.com", points: 50,
note: "強制退会" });
return memberListInit;
}
);
</script>
<template>
<div>
<TheBaseSection />
</div>
</template>
・TheBaseSection.vue(中コンポーネント)
TheBaseSection.vue
<script setup lang="ts">
import type { Member } from '@/interfaces';
import OneMember from './OneMember.vue';
// 会員情報リストを、ステートから取得する
const memberList = useState<Map<number, Member>>("memberList");
// 保有ポイントの合計算出
const totalPoints = computed(
(): number => {
let total = 0;
for (const member of memberList.value.values()) {
total += member.points;
}
return total;
}
);
</script>
<template>
<section>
<h1>会員リスト</h1>
<p>全会員の保有ポイント 合計: {{ totalPoints }}</p>
<!-- OneMember コンポーネント呼び出し -->
<OneMember
v-for="id in memberList.keys()"
v-bind:key="id"
v-bind:id="id" />
</section>
</template>
<style scoped>
section {border: orange 1px dashed; margin: 10px}
</style>
・OneMember.vue(最小コンポーネント)
OneMember.vue
<script setup lang="ts">
import type { Member } from '@/interfaces';
// Props インターフェイスを定義
interface Props {
id : number;
}
// Props オブジェクト設定
const props = defineProps<Props>();
// 会員情報リストを ステートから取得
const memberList = useState<Map<number, Member>>("memberList");
// 該当する会員情報の取得
const member = memberList.value.get(props.id) as Member;
// 備考(note) を加工する算出プロパティ
const localNote = computed(
(): string => {
let localNote = member.note;
// 備考がない場合
if(localNote == undefined) {
localNote = '--';
}
return localNote;
}
);
// ポイント加算 ボタン クリック
const pointUp = (): void => {
member.points+=1;
}
</script>
<template>
<section class="box">
<h4>{{ member.name }} さん</h4>
<dl>
<dt>ID</dt>
<dd>{{ id }}</dd>
<dt>メールアドレス</dt>
<dd>{{ member.email }}</dd>
<dt>保有ポイント</dt>
<dd>{{ member.points }}</dd>
<dt>備考</dt>
<dd>{{ localNote }}</dd>
</dl>
<button v-on:click="pointUp">ポイント加算</button>
</section> <!-- ========== section END ======== -->
</template>
<style scoped>
.box { border: green 1px solid;margin: 10px;}
</style>
・グローバル
interfaces.ts
export interface Member {
id: number;
name: string;
email: string;
points: number;
note?: string;
}