Cree componentes de UI con el HTML que ya tiene.
¡2kb Gzipped y 6kb minificado! ?
data en su HTML existente < div data-component =" Counter " >
< p data-bind =" state:Counter.count " > 0 </ p >
< button data-action =" click->Counter.decrement " >
-1
</ button >
< button data-action =" click->Counter.increment " >
+1
</ button >
</ div >class JavaScript? import { Component } from "domponent" ;
export default class Counter extends Component {
constructor ( el ) {
super ( el ) ;
}
increment ( ) {
this . setState ( { count : this . state . count + 1 } ) ;
}
decrement ( ) {
this . setState ( { count : this . state . count - 1 } ) ;
}
} import { Init } from "domponent" ;
import Counter from "./Counter.js" ;
const config = {
selector : document . getElementById ( "root" ) ,
components : {
Counter
} ,
appCreated : callbackFunction
} ;
new Init ( config ) ;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡!!
Esta biblioteca establece una forma limpia y moderna de convertir HTML prerendered en componentes de UI. Puede implementar fácilmente algunos datos de unión, manejar el alcance, pasar datos y crear componentes utilizando algunas de las convenciones en este script. Está destinado a ser una alternativa muy liviana a los estímulos con un poco de sabor react (métodos de ciclo de vida, accesorios y estado componente).
Domponent no maneja la representación del lado del cliente fuera de la caja, no crea DOM virtual, no difiere DOM (aunque difiere el estado y los accesorios). No está destinado a manejar el enrutamiento o el estado de aplicación completo. Está destinado a tomar fragmentos HTML (Thymeleaf, Rails, Pug, cualquier motor de plantilla que use) y crear funcionalidad reutilizable en forma de componentes.
Domponent es similar a Knockout de alguna manera:
A diferencia de Knockoutjs, Domponent:
Knockear
Html
< p > First name: < input data-bind =" value: firstName " /> </ p >
< p > Last name: < input data-bind =" value: lastName " /> </ p >
< h2 > Hello, < span data-bind =" text: fullName " > </ span > ! </ h2 >Js
var ViewModel = function ( first , last ) {
this . firstName = ko . observable ( first ) ;
this . lastName = ko . observable ( last ) ;
this . fullName = ko . pureComputed ( function ( ) {
return ` ${ this . firstName ( ) } ${ this . lastName ( ) } ` ;
} , this ) ;
} ;
ko . applyBindings ( new ViewModel ( "Planet" , "Earth" ) ) ;Dominio doméstico
Html
< div data-component =" Hello " data-state =" { " firstName ": "Planet", "lastName": "Earth"}" >
< p > First name: < input data-action =" input->Hello.setFirstName " /> </ p >
< p > Last name: < input data-action =" input->Hello.setLastName " /> </ p >
< h2 > Hello, < span data-bind =" state:Hello.fullName " > </ span > ! </ h2 >
</ div >Js
import { Component } from "domponent" ;
export default class Hello extends Component {
constructor ( conf ) {
super ( conf ) ;
}
setFirstName ( event ) {
this . setState ( { firstName : event . target . value } , ( ) => {
this . setFullName ( ) ;
} ) ;
}
setLastName ( event ) {
this . setState ( { lastName : event . target . value } , ( ) => {
this . setFullName ( ) ;
} ) ;
}
setFullName ( ) {
this . setState ( {
fullName : ` ${ this . state . firstName } ${ this . state . lastName } `
} ) ;
}
}https://tamb.github.io/domponent/
Lista de TODO: https://codesandbox.io/embed/domponent-todo-with-undo- redo-sp3s2?fontsize=14
Demostración local
git clone este repositorionpm installnpm run build:html-dev o npm run build:html-prod npm install -- save domponent Puede usar una versión ES5 importando este archivo domponent/dist/domponent.es5.production.min.js
Si no está utilizando un transpilador, se recomienda usar el ES5 UMD. Así que aquí está el enlace JSDelvr:
// production
< script type = "text/javascript" src = "https://cdn.jsdelivr.net/npm/domponent@VERSION/dist/domponent.es5.production.min.js" defer > </ script >
// development
< script type = "text/javascript" src = "https://cdn.jsdelivr.net/npm/domponent@VERSION/dist/domponent.es5.development.min.js" defer > < / script > Nota: Use tanto o tan poco de esta biblioteca como desee. Puede usar esto solo para data-component , data-ref y datos data-ref-array y facilitar su selección DOM. Puede hacer componentes sin estado con la clase Exponent . El cielo es el límite. En esencia, Domponent es un conjunto de clases de utilidad para su HTML.
data-component Usamos este chico malo para que coincida con el nombre del componente con su class correspondiente en el objeto de configuración Init
Ejemplo: si su html es data-component="Counter" | Debe tener un componente en su configuración llamado Counter
data-bind Une state o props al textContent de un elemento primero que especifica si desea unir state o props data-bind="state:Counter.count" o data-bind="props:Counter.count" : contador.
data-actionUne un evento DOM con un método de componente. Considere lo siguiente:
< button data-action =" click->Counter.increment " >
+1
</ button > La mitad izquierda de : representa la cadena literal para el evento DOM a escuchar. La mitad derecha corresponde al método de componente
Nota: Puede agregar varios oyentes con una tubería | ejemplo:
< button data-action =" click->Counter.increment|mouseover->Counter.anotherMethod " >
+1
</ button > También puede pasar las opciones de eventListener . Las opciones deben ser después de a . Después del método de clase. Las opciones deben estar separadas por una coma , .
< button
data-action =" click->Counter.increment.passive,capture|mouseover->Counter.anotherMethod.once,passive "
>
+1
</ button > data-state Si desea instanciar su componente con un estado particular en la memoria , debe adjuntar un atributo de data-state al elemento raíz del ejemplo del componente:
<div data-component="Counter" data-state='{"count":24, "isEven": true}'>
...
</div>
Así es. data-state toma cualquier objeto JSON válido.
data-ref Si necesita hacer referencia a DOM Elements, puede usar data-ref como así:
< div data-ref =" Counter.myElement " > </ div > Debe prefacio en qué componente se encuentra el elemento. Luego se almacena en el objeto componente $refs .
Luego puede acceder al elemento en Counter usando this.$refs.myElement dentro de la instancia del componente.
data-ref-arrayPuede crear una variedad de elementos en su componente de esta manera:
< div data-ref-array =" Counter.elements " > </ div >
< div data-ref-array =" Counter.elements " > </ div > Luego se almacena en el objeto componente $refs . Puede acceder a la variedad de elementos en su componente con this.$refs.elements .
data-key Esto es totalmente opcional. Es una cadena única para cada instancia de componente.
Esto se usa internamente para unir accesorios. Por lo tanto, debe conocer la $key del componente del que está recibiendo accesorios.
< div data-component =" Counter " data-key =" aUniqueKey " >
...
</ div >Supongamos que está pasando por esto en su lenguaje de plantilla. Debe asegurarse de que sus llaves sean únicas.
# for (let i=0; i < 10 ; i++){
< div data-component =" Counter " key =" `aUniqueKey${i}` " > ... </ div >
} Si no usa este atributo, se asignará una clave única a cada instancia de componente automáticamente. Se puede acceder a través de this.$key
data-props Puede compartir el estado de un componente principal como props en un componente infantil. El marcado se vería así
< div data-component =" Counter " key =" parentCounter " >
< div
data-props =" myAwesomeProp<-parentCounter:ofFive "
data-component =" DisplayAnything "
> </ div >
</ div > El lado izquierdo de la flecha <- es el nombre del accesorio en el componente DisplayAnything . El lado derecho de la flecha es $key del componente principal, un colon : y el nombre de la pieza de state para heredar.
Luego puede usar los métodos de ciclo de vida propsWillUpdate y propsDidUpdate para hacer cambios dentro de su componente infantil.
Component ?Continuemos con contador. El mínimo JS necesario para crear un componente está a continuación:
class Counter extends Component {
constructor ( conf ) {
super ( conf ) ;
}
} super agrega los métodos y propiedades base que su componente necesita.
No mutar el estado directamente. Llame a this.setState
setState ( stateObject , callbackFunction ) ;Esto es similar en concepto a SetState de React, aunque se implementa de manera diferente.
Puede agregar estados predeterminados a su componente JS y anularlos en el DOM
export default class Counter extends Component {
constructor ( conf ) {
super ( conf ) ;
this . state = {
count : parseInt ( this . state . count ) || 0 ,
isEven : this . state . count
? this . state . count % 2 === 0
? true
: false
: true ,
stateFieldFromDOM : this . state . stateFieldFromDOM || "default cat" ,
stateFieldDefault : "default iPhone 11"
} ;
this . setState ( this . state ) ;
} <div data-component="Counter" data-state="{"count": 4, "isEven":true, "stateFieldFromDOM": "some value here"}"
Los campos de estado anteriores anularán los campos de estado JS predeterminados.
El enlace de valor de setState siempre será para textContent . Si desea usar el estado/accesorios para representar HTML, puede agregar un observador para ese valor y actualizar el nodo $refs que albergará el nuevo HTML.
watch ( ) {
return {
count : {
post ( newCount ) {
this . $refs . exclaimCount . innerHTML = `<div class="uppercase"> ${ newcount } !</div>` ;
}
}
}
}Los siguientes son métodos que puede usar para acceder a los componentes en varios puntos de su ciclo de vida.
| Método de ciclo de vida | Contexto | Descripción |
|---|---|---|
| conexión | Componente/exponente | Antes de que la biblioteca aljee cualquiera de sus componentes/exponentes y tenga acceso a otros métodos |
| conectado | Componente/exponente | Después de que su componente/exponente esté conectado y todos los que se encuentren en su lugar |
| desconexión | Componente/exponente | Antes de eliminar las listas de eventos y eliminar el componente/exponente de la memoria |
| propswillupdate | Componente/exponente | Antes de que los accesorios se actualicen dentro de su componente, no han sucedido mutaciones DOM |
| propsdidupdate | Componente/exponente | Después de que los accesorios se hayan actualizado y el DOM ha cambiado |
| estatus | Componente | Antes de que el estado del componente actual o cualquiera de los accesorios de sus dependientes haya cambiado |
| STADIdUpdate | Componente | Los componentes infantiles con accesorios heredados han hecho sus manipulaciones DOM y el estado y los accesorios han cambiado |
Las clases Component y Exponent tienen un método watch que debe devolver un objeto. Los observadores le permiten conectarse a cambios de valor específicos state o props durante el estilo de vida del componente. Esto permite que su lógica estatal esté aislada en lugar de agruparla todo con stateWillUpdate , stateDidUpdate , propsWillUpdate o propsDidUpdate . Esto está destinado a imitar de cerca los observadores en Vue.JS Nota : No nombres a tu state y a los campos props de la misma manera. Esta es una mala práctica y romperá a los observadores.
watch ( ) {
return {
myField : {
pre ( newValue , oldValue ) {
// my logic
} ,
post ( newValue ) {
// my logic
}
}
}
} Puede ver sus campos estatales observados en el objeto componentes $watchers .
Extienda la clase Exponent para crear un componente con solo props esto es un peso ligeramente más ligero que un Component . Más rápido para conectar y toma menos memoria.
import { Exponent } from 'domponent'
class StatelessThing extends Exponent{
constructor(conf){
super(conf);
}
}
Entonces solo tendrás acceso a:
propsWillUpdatepropsDidUpdate ¿Por qué Exponent ?
Porque simplemente interpreta o expone los datos que se dan ... y suena como un componente.
Los componentes o exponentes recibirán los siguientes campos.
| Nombre de campo | Tipo | Acceso | Contexto | Descripción |
|---|---|---|---|---|
| $ aplicación | objeto | público | Componente/exponente | Toda la aplicación Domponent |
| $ B | formación | privado | Componente/exponente | EventListener enlaces para uso interno |
| $ D | objeto | privado | Componente | Los componentes principales se refieren a sus hijos |
| $ Key | cadena | público | Componente/exponente | Identificador único para la instancia de componente |
| $ Nombre | cadena | público | Componente/exponente | El nombre del tipo de componente |
| $ P | objeto | privado | Componente/exponente | Colección interna de accesorios y sus referencias DOM |
| accesorios | objeto | público | Componente/exponente | Pares de datos clave/valor aprobados |
| $ root | elemento | público | Componente/exponente | El nodo DOM raíz del componente |
| $ S | objeto | privado | Componente | Colección interna de Estado y sus referencias DOM |
| estado | objeto | público | Componente | Pares de datos clave/valor que se pueden actualizar |
| $ Watchers | objeto | público | Componente | Funciones de cambio almacenadas y su respectiva llave de estado y apoyo |
Init ? Esta función crea la aplicación y registra todos los componentes. Esto toma un objeto config como argumento requerido:
const config = {
selector : document . getElementById ( "root" ) ,
components : { Counter } ,
appCreated : callbackFunction
} ;
const App = new Init ( config ) ;Luego expone los siguientes métodos:
Y los siguientes objetos:
También puede excluir el objeto components de la configuración y crear una aplicación sin ningún componente para comenzar.
createComponent@params:
App . createComponent ( document . getElementById ( "added-html" ) , callback ) ; register@params
App . register ( NewComponent , callback ) ; deleteComponent@params:
data-key o el componente interno a través de this.$key App . deleteComponent ( "my-component-instance-key" , callback ) ; unregister@params:
App . unregister ( "NewComponent" , callback ) ; Para evitar los atributos data- , los atributos se enfrentan con otros selectores, bibliotecas, etc., puede anular los nombres de atributos predeterminados en el objeto de configuración de la aplicación:
Init ( {
selector : getElementById ( 'root),
components : { Counter } ,
dataAttributes : {
component : 'mynamespace-component' ,
state : 'cool-state' ,
}
} ) ;Esto significa que su HTML se verá así:
< div data-mynamespace-component =" Counter " data-cool-state =' {"count":12} ' >
...
</ div >Opcionalmente, puede personalizar la sintaxis que usa en su HTML. Los siguientes elementos se pueden personalizar.
INHERITS_FROM: '<-',
FROM_COMPONENT: '.',
KEY_VALUE: ':',
MULTIPLE_VALUES: "|",
METHOD_CALL: "->",
LIST: ","
Esto significa que en su configuración puede agregar:
{
customSyntax : {
LIST : "!" ,
METHOD_CALL : "#"
}
}¡Y tu HTML puede usar esto!
Cuando se desarrolla con Domponent, el uso de la compilación de desarrollo agrega errores y registros útiles a su consola de Desarrollo DOM (este tipo->)?
La forma más fácil de usar esto es con los alias de Webpack:
resolve : argv . mode === 'development' ? {
alias : {
domponent : 'domponent/dist/domponent.development.js'
}
} : { } ,De esta manera, su desarrollo de desarrollo de Webpack cambiará la versión de producción de Domponent por la versión rociada con ayuda de DOM.
Puede escribir su componente HTML para varios motores de plantilla e incluirlos como parciales/fragmentos/lo que sea que su motor se refiera como "trozos de HTML".
Aquí hay algunos ejemplos de cómo podría usar Domponent.
Nota: a pesar de estas diferencias de sintaxis en el marcado, recuerde que el componente es simplemente una clase JS ✌️
¿Ejemplo de sintaxis PUG ?
// counter.pug
mixin counter ( count )
div ( data - component = "Counter" data - state = `
{
"count": count,
"isEven": count % 2 === 0
}
` )
p ( data - bind = "state:Counter.count" ) # { count }
button ( data - action = "click->Counter.increment" ) + 1
button ( data - action = "click->Counter.decrement" ) - 1
// usage
+ counter ( 101119 )
+ counter ( 61316 )¿Ejemplo de sintaxis de Tymeleaf ?
// counter.html
< div
data-component =" Counter "
th:fragment =" Counter "
th:data-state =' |{"count":${count}, "isEven": ${count % 2 == 0}}| '
>
< p data-bind =" state:Counter.count " th:text =" ${count} " > </ p >
< button data-action =" click->Counter.increment " >
+1
</ button >
< button data-action =" click->Counter.decrement " >
-1
</ button >
</ div >
// usage
< th:block th:replace =" ./counter.html :: Counter(count: 1289) " />
< th:block th:replace =" ./counter.html :: Counter(count: 491) " />Ejemplo de sintaxis de afeitar ⚔️ Próximamente ...
¿Ejemplo de sintaxis de Ruby on Rails ? muy pronto...
¿Ejemplo de sintaxis de bigote ? muy pronto...
domponent [at] gmail [dot] com ( utilice el Domponent Support de sujetos o no responderemos )@domponent