Uma das vantagens de usar composables
em vue
é que você consegue justamente “compor” novos composables a partir de outros já existentes. Por exemplo, você pode criar um composable que fornece informações diferentes baseado na rota atual.
Vamos imaginar um cenário em que você tem um floating button
no seu site. Esse é um botão que está sempre presente no canto inferior direito da sua página, entretanto, o seu texto e comportamento precisam ser diferentes dependendo da página que o usuário está.
Uma solução seria criar o seguinte composable:
import { computed } from "vue";
import { useRoute } from "vue-router";
export default function useFloatingButton() {
const route = useRoute();
const contactPages = ["/about-us", "/contact-us"];
const mode = computed<"contact" | "login">(() => {
return contactPages.includes(route.path) ? "contact" : "login";
});
const buttonText = computed(() =>
mode.value === "contact" ? "Contact Us" : "Login"
);
const handleClick = () => {
if (mode.value === "contact") {
console.log("Contact action triggered");
} else {
console.log("Login action triggered");
}
};
return {
mode,
buttonText,
handleClick,
};
}
Problema resolvido, mas ainda podemos melhorar. O que aconteceria se você precisasse criar uma nova página que também usasse o modo contact
? Você teria que se lembrar de adicionar a nova rota ao array contactPages
, o que não é ideal. Para mim, o ideal seria que a própria rota soubesse qual é o seu modo. Para isso, podemos usar meta
do vue-router
.
const routes = [
{
path: "/",
name: "Home",
component: Home,
meta: { floatingButtonMode: "login" },
},
{
path: "/about-us",
name: "AboutUs",
component: AboutUs,
meta: { floatingButtonMode: "contact" },
},
{
path: "/contact-us",
name: "ContactUs",
component: ContactUs,
meta: { floatingButtonMode: "contact" },
},
];
Se você está usando TypeScript, pode adicionar um tipo para o meta das rotas:
declare module "vue-router" {
interface RouteMeta {
floatingButtonMode?: "login" | "contact";
}
}
Nesse caso, não se esqueça de adicionar o as const
na definição das rotas, senão o TypeScript
irá inferir o tipo como string
.
Agora podemos modificar nosso composable para usar o meta
da rota:
import { computed } from "vue";
import { useRoute } from "vue-router";
export default function useFloatingButton() {
const route = useRoute();
const mode = computed<"contact" | "login">(() => {
return route.meta.floatingButtonMode || "login";
});
const buttonText = computed(() =>
mode.value === "contact" ? "Contact Us" : "Login"
);
const handleClick = () => {
if (mode.value === "contact") {
console.log("Contact us action triggered");
} else {
console.log("Login action triggered");
}
};
return {
mode,
buttonText,
handleClick,
};
}
Nuxt
Utilizando Nuxt é ainda mais fácil implementar esse tipo de comportamento. O Nuxt disponibiliza um macro chamado definePageMeta
que permite definir metadados diretamente na página.
<script setup lang="ts">
definePageMeta({
floatingButtonMode: "contact",
});
</script>
Você pode adicionar tipagem para o meta
de forma similar ao vue-router
:
declare module "#app" {
interface PageMeta {
floatingButtonMode: "contact" | "login";
}
}