Mesin Templat Dom Virtual Tiny (512 Byte) untuk Proyek Tertanam
| Yaitu / tepi | Firefox | Chrome | Safari | Opera | ios safari | Chrome untuk Android |
|---|---|---|---|---|---|---|
| Tepi 14+ | 45+ | 49+ | 10+ | 37+ | 10.2+ | 55+ |
.DOM meminjam beberapa konsep dari React.js (seperti komponen yang dapat digunakan kembali dan DOM virtual) dan mencoba mereplikasi mereka dengan jejak sekecil yang mungkin, mengeksploitasi fitur JavaScript ES6.
Mengapa? Karena dengan perpustakaan seperti itu Anda dapat membuat GUI yang kuat di lingkungan ruang angkasa yang ketat, seperti perangkat IoT, di mana menghemat bahkan byte tambahan sebenarnya penting!
Tiny by Design : Perpustakaan tidak boleh melebihi ukuran 512 byte. Tujuannya bukan untuk memiliki mesin templat lain, tetapi untuk memiliki sebanyak mungkin fitur dalam 512 byte. Jika fitur baru diperlukan, yang lain harus disorot atau ruang lingkup harus dikurangi.
Dibangun untuk Masa Depan : Perpustakaan sangat mengeksploitasi spesifikasi ES6, yang berarti bahwa itu tidak didukung oleh browser yang lebih tua. Saat ini didukung oleh 90% browser di pasar, tetapi berharap ini mendekati 100% dalam tahun depan.
Deklaratif : Jelaskan DOM HTML Anda dengan cara yang terstruktur dan alami, membantu Anda membuat antarmuka pengguna yang kuat namun mudah dibaca.
Berorientasi Komponen : Sama seperti react.js, .dom mempromosikan penggunaan komponen fungsional.
Accelerators "Write Less" : API Perpustakaan dirancang khusus untuk memiliki nama dan akselerator fungsi pendek, yang memungkinkan Anda untuk menggambarkan pandangan Anda dengan lebih sedikit kode.
.dom Apakah Anda menggunakan .dom di proyek Anda? Parut repositori ini dan tambahkan milik Anda di daftar!
Untuk jejak minimum, sertakan dotdom.min.js.gz (512b) ke proyek Anda.
< script src =" dotdom.min.js.gz " />Atau Anda bisa memasukkan versi minified dari perpustakaan langsung sebelum skrip Anda. Cukup salin-paste kode yang diminified.
Jika Anda sudah tahu React.js, contoh -contoh berikut dapat membantu Anda memahami bagaimana primitif .dom berhubungan dengan bereaksi.
Memberikan struktur DOM yang sangat sederhana.
| Bereaksi | .dom |
|---|---|
ReactDOM . render (
React . createElement ( 'div' , null , 'Hello world' ) ,
document . body
) ; | R (
H ( 'div' , 'Hello world' ) ,
document . body
) |
Membuat komponen tempat Anda dapat melewati properti.
| Bereaksi | .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
) |
Menciptakan komponen yang dapat mempertahankan keadaan mereka sendiri.
| Bereaksi | .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
) |
Komponen ini juga dapat berlangganan acara siklus hidup:
| Bereaksi | .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
) |
Pembaruan terkunci adalah fitur rekonsiliasi yang berguna dari React yang memungkinkan mesin rendering untuk mengambil keputusan cerdas tentang elemen mana yang akan diperbarui.
Kasus yang sangat berguna adalah ketika Anda membuat daftar elemen yang dinamis. Karena mesin rendering tidak mengerti elemen mana yang telah berubah, itu berakhir dengan pembaruan yang salah.
Untuk menyelesaikan masalah ini, mesin VDOM menggunakan properti key yang secara unik mengidentifikasi elemen di pohon. Namun .dom menyelesaikannya, dengan menyimpan salinan status elemen dalam instance elemen vdom itu sendiri.
Ini berarti bahwa Anda tidak memerlukan properti key , pastikan Anda mengembalikan instance VDOM yang sama seperti sebelumnya.
Jika Anda membuat elemen dinamis (mis. Array elemen vdom), .Dom mungkin mengalami kesulitan mendeteksi urutan pembaruan yang benar.
| Bereaksi | .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
) |
Perhatikan bahwa solusi di atas akan memperbarui komponen stateful dengan benar, bahkan jika pesanan mereka telah berubah. Namun, jika Anda menginginkan fungsionalitas yang lengkap dan seperti reaksi yang memperbarui kunci individual, Anda dapat menggunakan 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 ) ) ;
} Anda dapat membuat node vdom mentah (tidak direkonsiliasi) (mis. Itu membawa konten html sewenang -wenang) dengan mengatur properti .r dari objek kait ke nilai kebenaran apa pun.
Ini akan menonaktifkan rekonsiliasi lebih lanjut ke node anak, dan karenanya menjaga konten Anda tetap utuh.
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 )Membuat pohon vnode yang diberikan ke elemen DOM yang diberikan. Pembaruan lebih lanjut dari komponen stateful hanya akan terjadi pada anak -anak dekat mereka.
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" } )Membuat elemen vnode. Jika string dilewatkan sebagai argumen pertama, itu akan membuat elemen HTML. Jika suatu fungsi diberikan, itu akan membuat komponen stateful.
Properti dan anak -anak bersifat opsional dan mereka dapat dihilangkan.
Alih-alih nama tag, Anda dapat memberikan fungsi yang mengembalikan DOM virtual sesuai dengan beberapa logika tingkat yang lebih tinggi. Fungsi seperti itu memiliki tanda tangan berikut:
const Component = ( props , state , setState , hooks ) {
// Return your Virtual DOM
return div ( ... )
} Properti props berisi objek properti seperti yang diberikan ketika komponen dibuat.
state diinisialisasi ke objek kosong {} dan diperbarui dengan memanggil metode setState({ newState }) . Yang terakhir juga akan memicu pembaruan untuk komponen dan anak -anak.
Anda juga dapat menetapkan properti ke objek state secara langsung jika Anda tidak ingin menyebabkan pembaruan.
Objek hooks dapat digunakan saat Anda ingin mendaftarkan penangan ke metode siklus hidup komponen.
Mirip dengan React, komponen .dom memiliki siklus hidup:
Untuk mengakses metode siklus hidup, Anda perlu menggunakan argumen keempat pada fungsi komponen Anda. Lebih khusus lagi Anda harus mendorong fungsi penanganan Anda di salah satu bidang berikut:
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' ) Fungsi steno dapat diekstraksi sebagai properti dari fungsi H Singkatan seperti itu berperilaku persis seperti H , tetapi dengan nama tag sudah diisi.
Disarankan untuk menggunakan tugas dekonstruktur di awal skrip Anda untuk membantu javascript lebih lanjut mengoptimalkan hasilnya:
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 ) Alih -alih memberikan className sebagai properti, Anda dapat menggunakan singkatan .className dalam kombinasi dengan metode tag steno.
Ini sama dengan memanggil div({className: 'className'}) dan antarmuka fungsi persis sama seperti di atas.
Catatan: Anda dapat menambahkan lebih dari satu kelas dengan menggabungkan lebih dari satu .class ke tag. Misalnya: div.foo.bar sama dengan div({className: 'foo bar'}) .
Karena fokus proyek adalah ukuran kecil, ia kurang cek kewarasan. Ini membuatnya rentan terhadap kesalahan. Berhati -hatilah dengan peringatan berikut:
Anda tidak dapat memicu pembaruan dengan penghapusan properti. Anda harus mengatur properti baru ke nilai kosong sebagai gantinya. Misalnya:
// Wrong
R ( div ( { className : 'foo' } ) , document . body ) ;
R ( div ( { } ) , document . body ) ;
// Correct
R ( div ( { className : 'foo' } ) , document . body ) ;
R ( div ( { className : '' } ) , document . body ) ; Anda tidak boleh menggunakan properti bernama $ di komponen Anda. Melakukannya, akan membuat objek properti dianggap sebagai simpul DOM virtual dan akan menghasilkan hasil yang tidak terduga.
// *NEVER* do this!
R ( H ( MyComponent , { $ : 'Foo' } ) , document . body ) K(state, components)Di
plugin-keyed.min.js
Memastikan keadaan komponen dalam daftar disinkronkan, sesuai dengan properti key mereka. Ini memungkinkan Anda untuk melakukan pembaruan kunci seperti reaksi seperti itu:
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 ) )
} Apakah Anda tertarik untuk berkontribusi pada .dom ? Anda lebih dari diterima! Pastikan untuk mengikuti pedoman:
npm install
npm test && npm run build && ls -l dotdom.min.js.gz
Jika tes lulus dan ukuran dotdom.min.js.gz lebih kecil dari atau sama dengan 512 byte, buat permintaan tarik. Kalau tidak, kurangi ruang lingkup Anda atau pikirkan implementasi lain untuk membawanya kembali ke 512 byte.
Pastikan untuk mengomentari kode Anda dengan benar, karena kemungkinan besar Anda harus melakukan peretasan JavaScript ekstrem. Gudeliens adalah sebagai berikut:
/**
* 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 */
...Lisensi di bawah lisensi Apache, Versi 2.0