Open4
Vue 動的コンポーネント切り替え
App.vue
<script setup lang="ts">
import { ref, computed } from 'vue'
import type { Ref, Component } from 'vue'
import NotePad from './NotePad.vue'
import Calculator from './Calculator.vue'
import Counter from './Counter.vue'
// コンポーネント配列を定義し、空でない配列を保証
const availableComponents: [Component, ...Component[]] = [NotePad, Calculator, Counter]
// 現在のインデックスを状態として管理
const currentIndex = ref(0)
// 現在のコンポーネントを取得
const currentComponent = computed(() => availableComponents[currentIndex.value])
// 前のコンポーネントに切り替える関数
const prevComponent = () => {
if (currentIndex.value > 0) {
currentIndex.value--
} else {
currentIndex.value = availableComponents.length - 1
}
}
// 次のコンポーネントに切り替える関数
const nextComponent = () => {
if (currentIndex.value < availableComponents.length - 1) {
currentIndex.value++
} else {
currentIndex.value = 0
}
}
</script>
<template>
<div class="container">
<div>
<component :is="currentComponent">{{ currentIndex }}</component>
</div>
<div class="navigation">
<button
@click="prevComponent"
class="nav-button"
>
<
</button>
{{ currentIndex }}
<button
@click="nextComponent"
class="nav-button"
>
>
</button>
</div>
</div>
</template>
<style scoped>
.container {
display: flex;
flex-direction: column;
align-items: center;
}
.navigation {
margin-top: 16px;
display: flex;
gap: 16px;
}
.nav-button {
background-color: #ffde57;
color: white;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
border: none;
transition: background-color 0.3s;
}
.nav-button:hover {
background-color: #306998;
}
.nav-button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
</style>
NotePad.vue
<script setup lang="ts"></script>
<template>
<div>
<slot />
ほげほげ
</div>
</template>
Calculator.vue
<script setup lang="ts"></script>
<template>
<div>
<slot />
ふがふが
</div>
</template>
Counter.vue
<script setup lang="ts"></script>
<template>
<div>
<slot />
ぴよぴよ
</div>
</template>
モチベーションは不明だけど、コンポーザブルに切り出してみる
useComponentSwitcher.ts
// composables/useComponentSwitcher.ts
import { ref, computed } from 'vue'
import type { Ref, Component } from 'vue'
export function useComponentSwitcher(components: [Component, ...Component[]]) {
const currentIndex = ref(0)
// 現在のコンポーネントを取得
const currentComponent = computed(() => components[currentIndex.value])
// 前のコンポーネントに切り替える関数
const prevComponent = () => {
if (currentIndex.value > 0) {
currentIndex.value--
} else {
currentIndex.value = components.length - 1
}
}
// 次のコンポーネントに切り替える関数
const nextComponent = () => {
if (currentIndex.value < components.length - 1) {
currentIndex.value++
} else {
currentIndex.value = 0
}
}
// 現在のインデックスと切り替え関数を返す
return {
currentComponent,
currentIndex,
prevComponent,
nextComponent,
}
}
App.vue
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useComponentSwitcher } from "./useComponentSwitcher"
import type { Ref, Component } from "vue"
import NotePad from './NotePad.vue';
import Calculator from './Calculator.vue';
import Counter from './Counter.vue';
const availableComponents: [Component, ...Component[]] = [NotePad, Calculator, Counter];
const { currentComponent, currentIndex, prevComponent, nextComponent } = useComponentSwitcher(availableComponents)
</script>
<template>
<div class="container">
<div>
<component :is="currentComponent">{{ currentIndex }}</component>
</div>
<div class="navigation">
<button
@click="prevComponent"
class="nav-button"
>
<
</button>
{{ currentIndex }}
<button
@click="nextComponent"
class="nav-button"
>
>
</button>
</div>
</div>
</template>
<style scoped>
.container {
display: flex;
flex-direction: column;
align-items: center;
}
.navigation {
margin-top: 16px;
display: flex;
gap: 16px;
}
.nav-button {
background-color: #ffde57; /* Pythonの黄色をイメージ */
color: white;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
border: none;
transition: background-color 0.3s;
}
.nav-button:hover {
background-color: #306998; /* Pythonの青をイメージ */
}
.nav-button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
</style>
ChatGPT に聞いたら頭よすぎ実装してくれた
全く理解できてない
const prevComponent = () => {
currentIndex.value = (currentIndex.value - 1 + components.length) % components.length
}
const nextComponent = () => {
currentIndex.value = (currentIndex.value + 1) % components.length
}