Ao trabalhar com projetos nos quais o SSR (Server Side Rendering) não é usado ou não é possível implementá-lo, surge o problema de que algumas funções ou lógica são gravadas duas vezes para elementos estáticos que imprimem back-end e para componentes que processam o Vue.
Por exemplo, precisamos implementar um componente de snippet de produto que possua vários requisitos:
- Ele pode ser impresso estaticamente a partir do back-end com todas as informações necessárias para SEO e lógica.
- Ele pode ser usado como um componente regular do Vue, passando parâmetros através do v-bind, anexando eventos de clique etc.
- Ele deve exibir o estado atual do botão de compra
- Depois de clicar no botão "Comprar", um pré-carregador deve aparecer aguardando o status da cesta
Uma solução:
- Escreva lógica para trechos estáticos anexando eventos de clique, adicione e remova classes de carregamento no botão Comprar
- Escreva separadamente um componente no Vue que implemente a mesma lógica apenas no formato do modelo
- Use o primeiro item para saída do back-end, o segundo, por exemplo, para saída de dados limpos obtidos do estado ou do ajax
Assim, escreveremos duas lógicas, uma trabalhará diretamente com o DOM, a outra com dados puros.
Minha solução para esse problema é usar slots, ou seja, a capacidade de definir o conteúdo padrão, que conterá parâmetros dinâmicos, mas, ao mesmo tempo, se o componente for usado como um modelo embutido, todos esses parâmetros serão substituídos pelos desenhados pelo back-end.
Vamos escrever um componente que possa lidar com estática e dinâmica:
Listagem de componentes<template> <div> <slot name="image"> <a :href="url" class="snippet__image"> <img :src="image"> </a> </slot> <slot name="title"> <a :href="url" class="snippet__title">{{ title }}</a> </slot> <div v-if="!inCart" @click="add" :class="{ 'snippet__buy--load': load }" class="snippet__control" > <slot name="button"> <div class="snippet__button"></div> </slot> </div> <div v-if="inCart" class="snippet__control"> <div class="snippet__button"></div> </div> <div v-if="load" class="snippet__load"></div> </div> </template> <script>
Usando um componente via back-end:
<snippet :id="1" class="snippet"> <a slot="image" href="#" class="snippet__image"> <img src="photo.jpg"> </a> <a slot="title" href="#" class="snippet__title"> 1</a> <div slot="button" class="snippet__button"></div> </snippet>
Usando um componente em outros componentes:
<catalog-list> <snippet v-for="item in items" :key="item.id" v-bind="item"></snippet> </catalog-list>
Agora, temos um componente que pode ser usado em diferentes casos.
Gostaria de ouvir sua opinião sobre essa abordagem, talvez haja uma solução melhor.