I'm currently working on setting up a slot machine-style animation using Vue 3, TailwindCSS, and HeadlessUI. At the moment, I have a simple green square that slides in from the top and out from the bottom based on cycles within a for-loop triggered by clicking the "click to transition" button. The resetIsShowing()
function is responsible for randomizing a sequential array (1-10). My objective is to display one of these 10 random numbers on the green square during each cycle. To achieve this, I modified the main div displaying the square to pass a random number during each cycle:
<div v-for="number in numbers" :key="number.id" class="h-full w-full rounded-md bg-green-500 shadow-lg">
{{ number }}
</div>
However, when I add the list property to the above div, I encounter the following error:
The current component <TransitionChild /> is rendering a "template".
However we need to passthrough the following props:
- ref
If I change "template" to "ref" in the TransitionRoot, I lose the desired slide down effect. How can I configure this setup so that numbers appear on the square with each cycle?
Below is the complete code:
<template>
<div class="flex flex-col items-center py-16">
<div class="h-72 w-72">
<div class="flex justify-center items-center w-full h-full p-4 text-9xl rounded-md shadow-lg border-solid border-2 border-sky-500">
<TransitionRoot
appear
:show="isShowing"
as="template"
enter="transition ease-in-out duration-300 transform"
enter-from="-translate-y-full opacity-0"
enter-to="translate-y-0 opacity-100"
leave="transition ease-in-out duration-300 transform"
leave-from="translate-y-0 opacity-100"
leave-to="translate-y-full opacity-0"
>
<div v-for="number in numbers" :key="number.id" class="h-full w-full rounded-md bg-green-500 shadow-lg">
{{ number }}
</div>
</TransitionRoot>
</div>
</div>
<button
@click="resetIsShowing"
class="mt-8 flex transform items-center rounded-full bg-black bg-opacity-20 px-3 py-2 text-sm font-medium text-white transition hover:scale-105 hover:bg-opacity-30 focus:outline-none active:bg-opacity-40"
>
<svg viewBox="0 0 20 20" fill="none" class="h-5 w-5 opacity-70">
<path
d="M14.9497 14.9498C12.2161 17.6835 7.78392 17.6835 5.05025 14.9498C2.31658 12.2162 2.31658 7.784 5.05025 5.05033C7.78392 2.31666 12.2161 2.31666 14.9497 5.05033C15.5333 5.63385 15.9922 6.29475 16.3266 7M16.9497 2L17 7H16.3266M12 7L16.3266 7"
stroke="currentColor"
stroke-width="1.5"
/>
</svg>
<span class="ml-3">Click to transition</span>
</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { TransitionRoot } from '@headlessui/vue'
const isShowing = ref(true)
const numbers = ref([])
const numberArray = ref(Array.from({length: 10}, (e, i)=> i + 1))
const sleep = (milliseconds) => {
return new Promise(resolve => setTimeout(resolve, milliseconds))
}
async function resetIsShowing() {
for (let i = 0; i < numberArray.value.length; i++) {
const index = Math.floor(Math.random() * numberArray.value.length)
await sleep(800)
isShowing.value = false
setTimeout(() => {
isShowing.value = true
}, 500)
numbers.value = numberArray.value.filter(r => r === (index + 1))
}
}
</script>