Componentes
Múltiplos slots
Tempo de leitura: 3 minutos
Vamos recapitular a solução que usamos na aula anterior para o componente Hero:
# ...
slot :inner_block, required: true
def hero(assigns) do
~H"""
<div class="bg-gray-800 text-white py-20">
<div class="container mx-auto text-center">
<h1 class="text-4xl font-bold"><%= render_slot(@inner_block) %></h1>
<p class="mt-4 text-lg">My personal website</p>
<.link
class="mt-8 bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded"
navigate={~p"/other"}
>
Get Started
</.link>
</div>
</div>
"""
end
# ...
Usamos o slot @inner_block
para renderizar o texto principal da página porém deixamos dois textos repetidos tanto na página inicial como na LiveView /other
. Isso gera mais confusão ainda pois, se você já estiver nesta página não há necessidade de você ver este link.
#Slots customizados
Por padrão todo componente terá um slot @inner_block
se houver algum HTML dentro de sua tag. Todavia, você também pode adicionar mais slots conforme necessário. Crie e execute custom_slots.exs
:
Mix.install([
{:liveview_playground, "~> 0.1.5"}
])
defmodule CustomRouter do
use LiveviewPlaygroundWeb, :router
pipeline :browser do
plug :accepts, ["html"]
end
scope "/" do
pipe_through :browser
live "/", IndexLive, :index
live "/other", OtherPageLive, :index
end
end
defmodule CoreComponents do
use LiveviewPlaygroundWeb, :html
slot :title
slot :subtitle
slot :inner_block
def hero(assigns) do
~H"""
<div class="bg-gray-800 text-white py-20">
<div class="container mx-auto text-center">
<h1 class="text-4xl font-bold"><%= render_slot(@title) %></h1>
<p class="mt-4 text-lg"><%= render_slot(@subtitle) %></p>
<%= render_slot(@inner_block) %>
</div>
</div>
"""
end
end
defmodule IndexLive do
use LiveviewPlaygroundWeb, :live_view
import CoreComponents
def render(assigns) do
~H"""
<.hero>
<:title>IndexLive</:title>
<:subtitle>Welcometo my personal website!</:subtitle>
<.link
class="mt-8 bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded"
navigate={~p"/other"}
>
Get Started
</.link>
</.hero>
<.link navigate={~p"/other"}>Go to other</.link>
"""
end
end
defmodule OtherPageLive do
use LiveviewPlaygroundWeb, :live_view
import CoreComponents
def render(assigns) do
~H"""
<.hero>
<:title>OtherPageLive</:title>
<:subtitle>You're on the first step!</:subtitle>
</.hero>
<.link navigate={~p"/"}>Go to home</.link>
"""
end
end
LiveviewPlayground.start(router: CustomRouter, scripts: ["https://cdn.tailwindcss.com"])
A primeira modificação que fizemos foi adicionar dois novos slot
na definição do nosso componente. Para deixar as coisas mais claras usamos os nomes :title
e :subtitle
para os novos slots.
A utilização de slots customizados é muito similar a sintaxe de componentes exceto que você deve usar :
. Quando colocamos texto em <:meu_slot>Abc</:meu_slot>
o código HEEx dentro dele irá ser enviado para este slot nomeado. Qualquer dado que não estiver dentro de um slot nomeado irá ser jogado no slot @inner_block
.
A função render_slot/2
consegue entender quando não há nada no slot. Na view OtherPageLive não adicionamos nada fora de slots nomeados e mesmo assim não houveram problemas no código.
#Resumindo!
- Componentes podem ter mais de um slot
-
Slots nomeados podem ser usados como
<:nome>Conteúdo</:nome>
e renderizados como<% render_slot(@nome) %>
. -
Qualquer HEEx fora de slots nomeados cai no slot
@inner_block
.
Feedback
Você tem algum feedback sobre esta página? Conte-nos!