Renderização Básica
Função h() e html (HTM Template Tag)
Section titled “Função h() e html (HTM Template Tag)”Slash oferece duas formas de criar elementos DOM: a função h() (hyperscript) e o template tag html (HTM).
HTM Template Tag (Recomendado)
Section titled “HTM Template Tag (Recomendado)”O template tag html permite escrever markup HTML-like diretamente no JavaScript/TypeScript sem necessidade de transpilação:
import { html } from '@ezbug/slash'
const element = html` <div class="container"> <h1>Hello, World!</h1> <p>This is a paragraph</p> </div>`Vantagens:
- Sintaxe familiar (similar a JSX)
- Sem build step necessário
- Type safety completo
- Syntax highlighting em editores modernos
Função h() (Hyperscript)
Section titled “Função h() (Hyperscript)”Para uma abordagem mais programática, use a função h():
import { h } from '@ezbug/slash'
const element = h('div', { class: 'container' }, h('h1', null, 'Hello, World!'), h('p', null, 'This is a paragraph'))Assinatura:
function h( tag: string | Component, props: Props | null, ...children: Child[]): NodeComparação: html vs h()
Section titled “Comparação: html vs h()”// HTMconst greeting = html` <div class="greeting"> <h1>Hello, ${name}!</h1> </div>`
// Hyperscript equivalenteconst greeting = h('div', { class: 'greeting' }, h('h1', null, `Hello, ${name}!`))Criando Elementos DOM
Section titled “Criando Elementos DOM”Elementos HTML Básicos
Section titled “Elementos HTML Básicos”import { html } from '@ezbug/slash'
// Div simplesconst div = html`<div>Content</div>`
// Com classesconst styled = html`<div class="container flex">Styled</div>`
// Com IDsconst unique = html`<div id="app">App Root</div>`
// Elementos vaziosconst input = html`<input type="text" />`const br = html`<br />`Elementos SVG
Section titled “Elementos SVG”Slash detecta automaticamente elementos SVG e aplica o namespace correto:
import { html } from '@ezbug/slash'
const icon = html` <svg width="24" height="24" viewBox="0 0 24 24"> <circle cx="12" cy="12" r="10" fill="blue" /> <path d="M12 6v6l4 2" stroke="white" stroke-width="2" /> </svg>`Tags SVG reconhecidas automaticamente: src/utils/constants.ts
svg,circle,path,rect,line,polyline,polygonellipse,text,g,defs,use,symbol,clipPathlinearGradient,radialGradient,stop,mask,pattern
Props e Children
Section titled “Props e Children”Props (Propriedades)
Section titled “Props (Propriedades)”Props são passadas como objeto no segundo argumento de h() ou como atributos no html:
// Com htmlconst button = html` <button class="btn btn-primary" disabled=${false} data-id="123" > Click Me </button>`
// Com h()const button = h('button', { class: 'btn btn-primary', disabled: false, 'data-id': '123'}, 'Click Me')Tipos de Props
Section titled “Tipos de Props”1. Atributos HTML
Section titled “1. Atributos HTML”const input = html` <input type="text" placeholder="Enter name" required=${true} maxlength="50" />`2. Properties JavaScript
Section titled “2. Properties JavaScript”Propriedades especiais são definidas via assignment direto:
const input = html` <input type="checkbox" checked=${true} value="option1" />`Properties especiais:
value(inputs, textarea, select)checked(checkbox, radio)selected(option)disabledclassName(alternativa aclass)
3. Classes
Section titled “3. Classes”Classes podem ser strings, arrays ou objetos:
// String simplesconst el1 = html`<div class="container"></div>`
// Array (classes condicionais)const classes = ['btn', isActive && 'active', 'large']const el2 = html`<button class=${classes}>Click</button>`
// Objeto (toggle classes)const classMap = { active: true, disabled: false, large: true }const el3 = html`<button class=${classMap}>Click</button>`Implementação: src/rendering/props-core.ts
4. Estilos
Section titled “4. Estilos”// String CSSconst el1 = html`<div style="color: red; font-size: 16px"></div>`
// Objeto CSSconst styles = { color: 'red', fontSize: '16px' }const el2 = html`<div style=${styles}></div>`Children (Filhos)
Section titled “Children (Filhos)”Children podem ser:
- Strings e números
- Elementos DOM (Node)
- Arrays (aninhados)
- Reactive/State (atualizados automaticamente)
null,undefined,false(ignorados)
import { html, createState } from '@ezbug/slash'
const count = createState(0)const name = "Alice"
const element = html` <div> <h1>Hello, ${name}!</h1> <p>Count: ${count}</p> ${count.get() > 5 && html`<p>Count is high!</p>`} <ul> ${[1, 2, 3].map(n => html`<li>Item ${n}</li>`)} </ul> </div>`Implementação: src/rendering/children.ts
Função render() para Montar na Página
Section titled “Função render() para Montar na Página”A função render() monta elementos no DOM:
import { render, html } from '@ezbug/slash'
const App = () => html` <div> <h1>My App</h1> </div>`
// Renderizar em elemento existenteconst root = document.getElementById('app')render(App(), root)
// Ou usando seletor CSSrender(App(), '#app')Assinatura
Section titled “Assinatura”function render( view: Child | (() => Child), container: Element | string | null | undefined): Node | Node[]Parâmetros:
view: Elemento ou função que retorna elementocontainer: Elemento DOM ou seletor CSS
Retorno: Node único ou array de Nodes inseridos
Implementação: src/rendering/render.ts
Comportamentos Especiais
Section titled “Comportamentos Especiais”Cleanup Automático
Section titled “Cleanup Automático”render() limpa children anteriores do container automaticamente:
const root = document.getElementById('app')
// Primeira renderizaçãorender(html`<div>First</div>`, root)
// Segunda renderização - remove 'First' antesrender(html`<div>Second</div>`, root)Hidratação SSR
Section titled “Hidratação SSR”Se o container já tem conteúdo renderizado pelo servidor E existe um <script id="__SLASH_STATE__">, render() hidrata em vez de substituir:
// Server-sideconst html = renderToString(App())const output = ` <div id="app">${html}</div> <script id="__SLASH_STATE__" type="application/json"> ${JSON.stringify(stateData)} </script>`
// Client-siderender(App(), '#app') // Hidrata DOM existenteErro Handling
Section titled “Erro Handling”render() valida o container e lança erros claros em dev mode:
// Container não encontradorender(App(), '#non-existent')// Error: [slash] render(): selector "#non-existent" not found
// Container nullrender(App(), null)// Error: [slash] render(): container Element is required (received null/undefined)Event Handlers
Section titled “Event Handlers”Event handlers são passados como props prefixadas com on:
Sintaxe Básica
Section titled “Sintaxe Básica”import { html, createState } from '@ezbug/slash'
const Counter = () => { const count = createState(0)
const increment = () => count.set(count.get() + 1) const decrement = () => count.set(count.get() - 1)
return html` <div> <p>Count: ${count}</p> <button onclick=${increment}>+</button> <button onclick=${decrement}>-</button> </div> `}Eventos Disponíveis
Section titled “Eventos Disponíveis”Todos os eventos DOM padrão são suportados:
const element = html` <input type="text" oninput=${(e) => console.log(e.target.value)} onchange=${handleChange} onfocus=${handleFocus} onblur=${handleBlur} onkeydown=${handleKeyDown} onkeyup=${handleKeyUp} />`Event Object
Section titled “Event Object”Event handlers recebem o evento nativo do browser:
const handleClick = (event: MouseEvent) => { console.log('Clicked at', event.clientX, event.clientY) event.preventDefault() event.stopPropagation()}
const button = html` <button onclick=${handleClick}>Click Me</button>`Event Options
Section titled “Event Options”Para opções avançadas, use array tuple [handler, options]:
const handleScroll = (e: Event) => { console.log('Scrolled')}
const container = html` <div onscroll=${[handleScroll, { passive: true, capture: false }]}> Content </div>`Event Options:
capture: boolean- Captura na fase de capturingpassive: boolean- Listener não chama preventDefault()once: boolean- Listener executado apenas uma vez
Implementação: src/rendering/events.ts
Form Events com Type Safety
Section titled “Form Events com Type Safety”import { html } from '@ezbug/slash'import type { TextFieldEvent } from '@ezbug/slash'
const handleInput = (e: TextFieldEvent<'input'>) => { const value = e.target.value // Type-safe access console.log('Input value:', value)}
const form = html` <form> <input type="text" oninput=${handleInput} /> </form>`Form event types: src/forms/form.types.ts
Cleanup de Event Listeners
Section titled “Cleanup de Event Listeners”Event listeners são automaticamente removidos quando um nó é destruído:
import { destroyNode } from '@ezbug/slash'
const button = html`<button onclick=${handler}>Click</button>`
// Quando não mais necessáriodestroyNode(button as Node) // Remove listener automaticamenteImplementação: src/lifecycle/cleanup.ts
Exemplos Práticos
Section titled “Exemplos Práticos”Exemplo 1: Botão com Estado
Section titled “Exemplo 1: Botão com Estado”import { html, createState, render } from '@ezbug/slash'
const ToggleButton = () => { const isActive = createState(false)
const toggle = () => isActive.set(!isActive.get())
return html` <button class=${isActive.get() ? 'active' : ''} onclick=${toggle} > ${isActive.get() ? 'Active' : 'Inactive'} </button> `}
render(ToggleButton(), '#app')Exemplo 2: Lista Dinâmica
Section titled “Exemplo 2: Lista Dinâmica”import { html, createState, render } from '@ezbug/slash'
const TodoList = () => { const todos = createState<string[]>(['Buy milk', 'Walk dog']) const input = createState('')
const addTodo = () => { const value = input.get().trim() if (value) { todos.set([...todos.get(), value]) input.set('') } }
return html` <div> <h1>Todos</h1> <ul> ${todos.get().map(todo => html`<li>${todo}</li>`)} </ul> <input type="text" value=${input} oninput=${(e: Event) => input.set((e.target as HTMLInputElement).value)} /> <button onclick=${addTodo}>Add</button> </div> `}
render(TodoList(), '#app')Exemplo 3: Form com Validação
Section titled “Exemplo 3: Form com Validação”import { html, createState, render } from '@ezbug/slash'
const LoginForm = () => { const email = createState('') const password = createState('') const error = createState('')
const handleSubmit = (e: Event) => { e.preventDefault()
if (!email.get().includes('@')) { error.set('Invalid email') return }
if (password.get().length < 6) { error.set('Password must be at least 6 characters') return }
error.set('') console.log('Login:', { email: email.get(), password: password.get() }) }
return html` <form onsubmit=${handleSubmit}> <h1>Login</h1> ${error.get() && html`<p class="error">${error}</p>`} <input type="email" placeholder="Email" value=${email} oninput=${(e: Event) => email.set((e.target as HTMLInputElement).value)} /> <input type="password" placeholder="Password" value=${password} oninput=${(e: Event) => password.set((e.target as HTMLInputElement).value)} /> <button type="submit">Login</button> </form> `}
render(LoginForm(), '#app')Próximos Passos
Section titled “Próximos Passos”Agora que você domina renderização básica, explore:
- Sistema de Estado - State management reativo avançado
- Componentes - Criar componentes reutilizáveis
- Batch Updates - Otimizar múltiplas atualizações