Um pequeno mecanismo de modelo Virtual DOM (512 byte) para projetos incorporados
| Ou seja, Edge | Firefox | Cromo | Safári | Ópera | iOS Safari | Chrome para Android |
|---|---|---|---|---|---|---|
| Edge 14+ | 45+ | 49+ | 10+ | 37+ | 10.2+ | 55+ |
.DOM empréstimo em deira alguns conceitos do React.js (como os componentes reutilizáveis e o DOM virtual) e tenta replicá-los com a menor pegada possível, explorando os recursos do JavaScript ES6.
Por que? Porque com essa biblioteca você pode criar GUIs poderosos em ambientes espaciais apertados, como dispositivos de IoT, onde salvar até um byte extra realmente importa!
Pequeno por design : a biblioteca nunca deve exceder os 512 bytes de tamanho. O objetivo não é ter outro mecanismo de modelo, mas ter o maior número possível de recursos em 512 bytes. Se for necessário um novo recurso, um outro deve ser sacrafado ou o escopo deve ser reduzido.
Construído para o futuro : a biblioteca está explorando fortemente as especificações do ES6, o que significa que não é suportado por navegadores mais antigos. Atualmente, é apoiado pelos 90% dos navegadores no mercado, mas espera que isso esteja próximo de 100% no próximo ano.
Declarativo : descreva seu HTML DOM de maneira estruturada e natural, ajudando você a criar interfaces de usuário poderosas, porém legíveis.
Orientado pelo componente : Assim como o React.js, o .DOM promove o uso de componentes funcionais.
"Escreva menos" aceleradores : a API da biblioteca foi projetada especificamente para ter nomes e aceleradores de funções curtas, permitindo que você descreva suas visualizações com menos código.
.dom Você está usando .dom em seu projeto? Bire este repositório e adicione o seu na lista!
Para a pegada mínima, inclua dotdom.min.js.gz (512b) no seu projeto.
< script src =" dotdom.min.js.gz " />Como alternativa, você pode incluir a versão minificada da biblioteca diretamente antes do seu script. Basta copiar cola o código minificado.
Se você já sabe o React.js, os seguintes exemplos podem ajudá -lo a entender como os primitivos .dom se relacionam com reagir.
Tornando uma estrutura DOM muito simples.
| Reagir | .dom |
|---|---|
ReactDOM . render (
React . createElement ( 'div' , null , 'Hello world' ) ,
document . body
) ; | R (
H ( 'div' , 'Hello world' ) ,
document . body
) |
Criando um componente no qual você pode passar propriedades.
| Reagir | .dom |
|---|---|
function Hello ( props ) {
return React . createElement (
'div' , null , `Hello ${ props . toWhat } `
) ;
}
ReactDOM . render (
React . createElement (
Hello , { toWhat : 'World' } , null
) ,
document . body
) ; | function Hello ( props ) {
return H ( 'div' , `Hello ${ props . toWhat } ` ) ;
}
R (
H ( Hello , { toWhat : 'World' } ) ,
document . body
) |
Criando componentes que podem manter seu próprio estado.
| Reagir | .dom |
|---|---|
class Clickable extends React . Component {
constructor ( ) {
super ( ... arguments ) ;
this . state = {
clicks : 0
} ;
}
render ( ) {
const { clicks } = this . state ;
return React . createElement (
'button' , {
onClick ( ) {
this . setState ( { clicks : clicks + 1 } )
}
} , `Clicked ${ clicks } times`
) ;
}
}
ReactDOM . render (
React . createElement ( 'div' , null ,
React . createElement ( Clickable , null , null ) ,
React . createElement ( Clickable , null , null )
) ,
document . body
) ; | function Clickable ( props , state , setState ) {
const { clicks = 0 } = state ;
return H ( 'button' ,
{
onclick ( ) {
setState ( { clicks : clicks + 1 } )
}
} ,
`Clicked ${ clicks } times`
) ;
}
R (
H ( 'div' ,
H ( Clickable ) ,
H ( Clickable )
) ,
document . body
) |
O componente também pode se inscrever nos eventos do ciclo de vida:
| Reagir | .dom |
|---|---|
class WithLifeCycle extends React . Component {
constructor ( ) {
super ( ... arguments ) ;
this . state = {
mounted : "no"
} ;
}
componentDidMount ( ) {
this . setState ( { mounted : "yes" } )
}
render ( ) {
const { mounted } = this . state ;
return React . createElement (
'div' , null , `mounted = ${ mounted } `
) ;
}
}
ReactDOM . render (
React . createElement ( 'div' , null ,
React . createElement ( WithLifeCycle , null , null ) ,
) ,
document . body
) ; | function WithLifeCycle ( props , state , setState , hooks ) {
const { mounted = "no" } = state ;
hooks . m . push ( ( ) => {
setState ( { mounted : "yes" } )
} ) ;
return H ( 'div' ,
`mounted = ${ mounted } `
) ;
}
R (
H ( 'div' , H ( WithLifeCycle ) ) ,
document . body
) |
As atualizações com chave é um recurso de reconciliação útil do React que permite que o mecanismo de renderização tome decisões inteligentes sobre quais elementos atualizarem.
Um caso particularmente útil é quando você está renderizando uma lista dinâmica de elementos. Como o mecanismo de renderização não entende qual elemento mudou, ele acaba com atualizações incorretas.
Para resolver esse problema, os motores VDOM usam uma propriedade key que identifica exclusivamente um elemento na árvore. No entanto .
Isso significa que você não precisa de nenhuma propriedade key , apenas certifique -se de retornar a mesma instância do VDOM de antes.
Se você estiver criando elementos dinâmicos (por exemplo, uma matriz de elementos VDOM), o .dom pode ter problemas para detectar o pedido de atualização correto.
| Reagir | .dom |
|---|---|
class Clickable extends React . Component {
constructor ( ) {
super ( ... arguments ) ;
this . state = {
clicks : 0
} ;
}
render ( ) {
const { clicks } = this . state ;
const { ket } = this . props ;
return React . createElement (
'button' , {
onClick ( ) {
this . setState ( { clicks : clicks + 1 } )
}
} , `clicks= ${ clicks } , key= ${ key } `
) ;
}
}
const list = [ "first" , "second" , "third" ] ;
const components = list . map ( key =>
React . createElement ( Clickable , { key } , null ) ;
ReactDOM . render (
React . createElement ( 'div' , null ,
components
) ,
document . body
) ; | function Clickable ( props , state , setState ) {
const { clicks = 0 } = state ;
const { key } = props ;
return H ( 'button' ,
{
onclick ( ) {
setState ( { clicks : clicks + 1 } )
}
} ,
`clicks= ${ clicks } , key= ${ key } `
) ;
}
const list = [ "first" , "second" , "third" ] ;
const components = list . map ( key =>
H ( Clickable , { key } ) ;
R (
H ( 'div' , components ) ,
document . body
) |
Observe que a solução acima atualizará corretamente os componentes com estado, mesmo que o pedido tenha sido alterado. No entanto, se você deseja a funcionalidade completa e semelhante a reação que atualiza as teclas individuais, você pode usar o plug-in Keyed .
function Container ( props , state ) {
const { components } = props ;
// The function `K` accepts the component state and an array of components that
// contain the `key` property, and returns the same array of components, with their
// state correctly manipulated.
return H ( "div" , K ( state , components ) ) ;
} Você pode criar nós VDOM RAW (não reconciliado) (por exemplo, que carregam um conteúdo HTML arbitrário) definindo a propriedade .r do objeto de ganchos para qualquer valor verdadeiro.
Isso desativará uma reconciliação adicional aos nós da criança e, portanto, manterá seu conteúdo intacto.
function Description ( props , state , setState , hooks ) {
const { html } = props ;
hooks . r = 1 ; // Enable raw mode
return H ( 'div' , {
innerHTML : html
} )
} R( VNode, DOMElement ) R ( H ( 'div' , 'Hello' ) , document . body )Renderiza a árvore vNode dada ao elemento DOM fornecido. Atualizações adicionais de componentes estabelecidos só ocorrerão em seus filhos imediatos.
H( tagName | function, [properties], [children ...]) H ( 'tag' )
H ( 'tag' , { prop : "value" } )
H ( 'tag' , H ( 'child' ) )
H ( 'tag' , { prop : "value" } , H ( 'child' ) )
H ( Component , { prop : "value" } )Cria um elemento vNode. Se uma string for passada como o primeiro argumento, ela criará um elemento HTML. Se uma função for dada, ela criará um componente com estado.
Propriedades e crianças são opcionais e podem ser omitidas.
Em vez de um nome de tag, você pode fornecer uma função que retorna um DOM virtual de acordo com uma lógica de nível superior. Essa função tem a seguinte assinatura:
const Component = ( props , state , setState , hooks ) {
// Return your Virtual DOM
return div ( ... )
} A propriedade props contém o objeto Propriedades, conforme dado quando o componente foi criado.
O state é inicializado para um objeto vazio {} e é atualizado chamando o método setState({ newState }) . O último também desencadeará uma atualização para o componente e suas crianças.
Você também pode atribuir propriedades ao objeto state diretamente se não quiser causar uma atualização.
O objeto hooks pode ser usado quando você deseja registrar manipuladores nos métodos do ciclo de vida do componente.
Semelhante ao React, os componentes .dom têm um ciclo de vida:
Para acessar os métodos do ciclo de vida, você precisa usar o quarto argumento na sua função de componente. Mais especificamente, você deve pressionar sua função de manuseio em qualquer um dos seguintes campos:
const Component = ( props , state , setState , hooks ) {
hooks . m . push ( ( domElement ) => {
// '.m' is called when the component is mounted
} ) ;
hooks . u . push ( ( ) => {
// `.u` is called when the component is unmounted
} ) ;
hooks . d . push ( ( domElement , previousDomElement ) => {
// `.d` is called when the component is updated
} ) ;
...
}tag( [properties], [children ...] ) const { div , span , a } = H ;
div ( 'hello' , span ( 'world' ) )
div ( 'click' , a ( { href : '#' } , 'Here' ) , 'to continue' ) Uma função abreviada pode ser extraída como uma propriedade da função H Tais abrevias se comportam exatamente como H , mas com o nome da tag já preenchido.
É recomendável usar uma tarefa de desconstrutura no início do seu script, a fim de ajudar os minificadores JavaScript a otimizar ainda mais o resultado:
const {div, span, a, button} = H;
tag.class( [properties], [children ...] ) const { h1 , span , p } = H ;
h1 . short ( 'short header' , span . strong ( 'strong text' ) )
button . primary ( { onclick : handleClick } , 'Primary Action' )
p . bold . italic ( twitterPost ) Em vez de fornecer o className como uma propriedade, você pode usar a abreviação .className em combinação com os métodos de tag de abreviação.
É o mesmo que chamar div({className: 'className'}) e a interface da função é exatamente a mesma que acima.
Nota: Você pode adicionar mais de uma classe concatenando mais de uma .class à tag. Por exemplo: div.foo.bar é o mesmo que div({className: 'foo bar'}) .
Como o foco do projeto é o tamanho pequeno, ele não tem verificações de sanidade. Isso o torna suscetível a erros. Tenha muito cuidado com as seguintes advertências:
Você não pode acionar uma atualização com uma remoção de propriedades. Você deve definir a nova propriedade como um valor vazio. Por exemplo:
// Wrong
R ( div ( { className : 'foo' } ) , document . body ) ;
R ( div ( { } ) , document . body ) ;
// Correct
R ( div ( { className : 'foo' } ) , document . body ) ;
R ( div ( { className : '' } ) , document . body ) ; Você nunca deve usar uma propriedade chamada $ em seus componentes. Fazer isso, fará com que o objeto da propriedade seja considerado um nó DOM virtual e levará a resultados inesperados.
// *NEVER* do this!
R ( H ( MyComponent , { $ : 'Foo' } ) , document . body ) K(state, components)No
plugin-keyed.min.js
Garante que o estado dos componentes da lista seja sincronizado, de acordo com sua propriedade key . Isso permite que você faça atualizações com chave semelhante a reagir como assim:
function ValueRenderer ( ... ) {
...
}
function MyComponent ( props , state ) {
const { values } = props ;
const components = values . map ( value => {
H ( ValueRenderer , {
key : value ,
value : value
} ) ;
} )
// Synchronize state of components, based on their key
return H ( 'div' , K ( state , components ) )
} Você está interessado em contribuir para .dom ? Você é mais do que bem -vindo! Apenas certifique -se de seguir as diretrizes:
npm install
npm test && npm run build && ls -l dotdom.min.js.gz
Se os testes passarem e o tamanho de dotdom.min.js.gz for menor ou igual a 512 bytes, crie uma solicitação de tração. Caso contrário, reduza seu escopo ou pense em outra implementação para reduzi -lo a 512 bytes.
Certifique -se de comentar adequadamente seu código, pois você provavelmente terá que fazer um hacking extremo de JavaScript. Os gudeliens são os seguintes:
/**
* Functions are commented as JSDoc blocks
*
* @param {VNode|Array<VNode>} vnodes - The node on an array of nodes to render
* ...
*/
global . R = render = (
vnodes , // Flat-code comments start on column 70 and
dom , // wrap after column 120.
/* Logical separations can be commented like this */
...Licenciado sob a licença Apache, versão 2.0