<template>
<div class="h-screen flex flex-no-wrap items-center mx-20 relative">
<div class="inline-flex">
<ul
class="relative z-20 uppercase font-extrabold list-none flex overflow-x-auto whitespace-no-wrap"
>
<li
v-for="category in categories"
:id="`category${category.name}`"
:key="category.url"
class="inline-flex mr-3 last:m-0 justify-center items-center text-center align-middle px-6 py-3 cursor-pointer rounded-full"
:class="{
'text-white': selectedCategory.name === category.name,
'hover:bg-gray-200 text-blue-900':
selectedCategory.name !== category.name
}"
@click="selectedCategoryChanged(category)"
>
<span>{{ category.name }}</span>
</li>
</ul>
<span
id="categoryBackground"
role="presentation"
class="transition-all duration-300 ease-in-out z-0 absolute rounded-full bg-red-700"
/>
</div>
</div>
</template>
<script>
import { ref, computed } from "vue";
export default {
setup() {
const categories = computed(() => {
return [
{
name: "bulbasaur",
url: "https://pokeapi.co/api/v2/pokemon/1/"
},
{
name: "charmander",
url: "https://pokeapi.co/api/v2/pokemon/4/"
},
{
name: "squirtle",
url: "https://pokeapi.co/api/v2/pokemon/7/"
},
{
name: "jigglypuff",
url: "https://pokeapi.co/api/v2/pokemon/39/"
},
{
name: "vulpix",
url: "https://pokeapi.co/api/v2/pokemon/37/"
},
{
name: "meowth",
url: "https://pokeapi.co/api/v2/pokemon/52/"
},
{
name: "rapidash",
url: "https://pokeapi.co/api/v2/pokemon/78/"
},
{
name: "dewgong",
url: "https://pokeapi.co/api/v2/pokemon/87/"
},
{
name: "jolteon",
url: "https://pokeapi.co/api/v2/pokemon/135/"
},
{
name: "spearow",
url: "https://pokeapi.co/api/v2/pokemon/21/"
},
{
name: "ekans",
url: "https://pokeapi.co/api/v2/pokemon/23/"
},
{
name: "pikachu",
url: "https://pokeapi.co/api/v2/pokemon/25/"
},
{
name: "sandshrew",
url: "https://pokeapi.co/api/v2/pokemon/27/"
},
{
name: "clefairy",
url: "https://pokeapi.co/api/v2/pokemon/35/"
}
];
});
let selectedCategoryName = ref("bulbasaur");
const selectedCategory = computed(() => {
// Here, we're using nextTick() to check that Vue has had time to render the categories in the DOM
Vue.nextTick(() => {
updateCategoryBackground(
categories.value.find(
(cat) => cat.name === selectedCategoryName.value
)
);
});
return categories.value.find(
(cat) => cat.name === selectedCategoryName.value
);
});
const categoryBackground = computed(() =>
document.querySelector(`#categoryBackground`)
);
let selectedCategoryElement = document.querySelector(
`#category${selectedCategory.value.name}`
);
function selectedCategoryChanged(category) {
// This function could also contain a store dispatch to hold details of the selected category
selectedCategoryName.value = category.name;
updateCategoryBackground(category);
}
function updateCategoryBackground(category) {
selectedCategoryElement = document.querySelector(
`#category${category.name}`
);
if (selectedCategoryElement && categoryBackground.value) {
categoryBackground.value.style.width =
selectedCategoryElement.scrollWidth + "px";
categoryBackground.value.style.height =
selectedCategoryElement.scrollHeight + "px";
categoryBackground.value.style.left = selectedCategoryElement.offsetLeft + "px";
}
}
return { categories, selectedCategory, selectedCategoryChanged };
}
};
</script>
This Pen doesn't use any external JavaScript resources.