O Virtual DOM é uma representação JavaScript da estrutura DOM real. Trata-se de um objeto simples contendo três propriedades essenciais: tag, props e children.
Considere o seguinte trecho HTML:
<section id="container">
<span class="label">exemplo</span>
</section>
Essa estrutura pode ser representada como um objeto JavaScript:
{
tag: "section",
props: {
id: "container"
},
children: [
{
tag: "span",
props: {
class: "label"
},
children: [
"exemplo"
]
}
]
}
Como o DOM possui uma estrutura hierárquica, é possível representá-lo por meio de objetos JavaScript. Os elementos nativos do navegador carregam consigo inúmeras propriedades e eventos — até mesmo um elemento vazio exige recrusos consideráveis.
A vantagem do Virtual DOM está na performance: quando ocorrem mudanças, o algoritmo de comparação (diff) identifica exatamente quais nós precisam ser atualizados, evitando re-renderizações desnecessárias da página inteira.
- A Função h no Vue
No Vue, a função h é um alias para createElement. Seu propósito é gerar nós virtuais (VNodes) que descrevem o que deve ser exibido na tela.
Ao configurar uma instância do Vue, frequentemente utilizamos a opção render:
const instancia = new Vue({
render: function(criarElemento) {
return criarElemento(MeuComponente)
}
})
- Compilação de JSX
Ao escrever JSX em um arquivo como principal.jsx:
function montarEstrutura() {
return (
<div id="container">
<p class="mensagem">Olá mundo</p>
</div>
)
}
O Babel transforma esse código em chamadas à função h:
function montarEstrutura() {
return h("div", {
id: "container"
}, h("p", {
class: "mensagem"
}, "Olá mundo"))
}
A função h pode ser implementada da seguinte forma:
function h(etiqueta, atributos, ...descendentes) {
return {
tag: etiqueta,
props: atributos || {},
children: descendentes.flat()
}
}
De acordo com a documentação oficial, createElement não retorna um elemento DOM real. O resultado é chamado de descrição de criação de nó (createNodeDescription), pois contém apenas as informações necessárias para que o Vue saiba qual estrutura renderizar. Esses objetos são denominados VNodes (nós virtuais).
- Parâmetros da Função createElement
A função createElement aceita três argumentos:
- Primeiro argumento — nome da tag, objeto de opções de componente ou função (obrigatório);
- Segundo argumento — objeto com atributos e propriedades do elemento (opcional);
- Terceiro argumento — nós filhos, podendo ser uma string ou array de VNodes (opcional).
Exemplo compartaivo entre template e render function:
<!-- Usando template -->
<div id="app">
{{titulo}}
<span>{{descricao}}</span>
</div>
<!-- Usando render function -->
render: function(criarElemento) {
return criarElemento("div", { id: "app" }, [
this.titulo,
criarElemento("span", this.descricao)
])
}
Observe que, quando o elemento pai possui texto diretamente, esse conteúdo deve vir como primeiro item do array no terceiro argumento.
- Renderização Condicional com Render Functions
<!-- Template equivalente -->
<ul v-if="lista.length">
<li v-for="item in lista">{{ item.nome }}</li>
</ul>
<p v-else>Nenhum registro</p>
<!-- Render function -->
data: {
lista: [
{ nome: "Ana" },
{ nome: "Bruno" },
{ nome: "Carlos" }
]
},
render: function(criarElemento) {
if (this.lista.length) {
return criarElemento("ul", this.lista.map(function(item) {
return criarElemento("li", item.nome)
}))
} else {
return criarElemento("p", "Nenhum registro")
}
}