埋め込まれたプロジェクト用の小さな(512バイト)仮想DOMテンプレートエンジン
| IE / EDGE | Firefox | クロム | サファリ | オペラ | iOSサファリ | Android用のChrome |
|---|---|---|---|---|---|---|
| エッジ14+ | 45+ | 49+ | 10+ | 37+ | 10.2+ | 55+ |
.DOMは、React.js(再利用可能なコンポーネントや仮想DOMなど)からいくつかの概念を借用し、ES6 JavaScriptの機能を活用して、可能な限り少ないフットプリントでそれらを複製しようとします。
なぜ?このようなライブラリを使用すると、IoTデバイスなどのタイトなスペース環境で強力なGUIを作成できるため、実際に追加のバイトを保存することが重要です。
デザインによって小さく:ライブラリのサイズが512バイトを超えないでください。目標は、さらに別のテンプレートエンジンを持つことではなく、512バイトにできるだけ多くの機能を持つことです。新しい機能が必要な場合は、他の機能をsacraficeしなければならないか、スコープを削減する必要があります。
将来のために構築された:ライブラリは、ES6仕様を大幅に活用しています。つまり、古いブラウザーではサポートされていません。現在、市場のブラウザの90%によってサポートされていますが、来年には100%に近いと予想されています。
宣言:HTML Domを構造化された自然な方法で説明し、強力で読みやすいユーザーインターフェイスを作成するのに役立ちます。
コンポーネント指向:React.jsのように、 。
「書き込み少ない」アクセラレータ:ライブラリAPIは、短い関数名とアクセラレータを持つように特別に設計されており、コードを少なくしてビューを説明できるようにします。
.domを使用したプロジェクトあなたはあなたのプロジェクトで.domを使用していますか?このリポジトリをフォークし、リストに追加してください!
最小限のフットプリントについては、プロジェクトにdotdom.min.js.gz (512b)を含めます。
< script src =" dotdom.min.js.gz " />または、スクリプトの直前にライブラリの削除バージョンを含めることもできます。マニファイ付きコードをコピーするだけです。
React.jsを既に知っている場合、次の例は、.domプリミティブが反応にどのように関係するかを理解するのに役立ちます。
非常にシンプルなDOM構造をレンダリングします。
| 反応します | .dom |
|---|---|
ReactDOM . render (
React . createElement ( 'div' , null , 'Hello world' ) ,
document . body
) ; | R (
H ( 'div' , 'Hello world' ) ,
document . body
) |
プロパティを渡すことができるコンポーネントを作成します。
| 反応します | .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
) |
独自の状態を維持できるコンポーネントを作成します。
| 反応します | .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
) |
コンポーネントは、ライフサイクルイベントを購読することもできます。
| 反応します | .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
) |
キー付き更新は、レンダリングエンジンが更新する要素についてスマートな決定を下すことを可能にするReactからの便利な調整機能です。
特に有用なケースは、要素の動的リストをレンダリングする場合です。レンダリングエンジンはどの要素が変更されたかを理解していないため、間違った更新で終わります。
この問題を解決するために、VDOMエンジンは、ツリー内の要素を一意に識別するkeyプロパティを使用します。ただし、vdom要素インスタンス自体に要素状態のコピーを保持することにより、 DOMはそれを解決します。
これは、 keyプロパティが必要ないことを意味します。以前と同じVDOMインスタンスを返すようにしてください。
動的要素(たとえば、VDOM要素の配列)を作成している場合、 .DOMは正しい更新順序の検出に問題がある場合があります。
| 反応します | .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
) |
上記のソリューションは、たとえ注文が変更されたとしても、ステートフルコンポーネントを正しく更新することに注意してください。ただし、個々のキーを更新する完全な反応のような機能が必要な場合は、 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 ) ) ;
} フックオブジェクトの.rプロパティを真理値に設定することにより、生の(繰り返し)vdomノード(任意のHTMLコンテンツを運ぶなど)を作成できます。
これにより、子ノードへのさらなる調整が無効になるため、内容物をそのまま保持します。
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 )指定されたvNodeツリーを指定されたDOM要素にレンダリングします。ステートフルコンポーネントからのさらなる更新は、直接の子供にのみ発生します。
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" } )VNode要素を作成します。文字列が最初の引数として渡されると、HTML要素が作成されます。関数が指定されている場合、ステートフルコンポーネントが作成されます。
プロパティと子供はオプションであり、省略できます。
タグ名の代わりに、いくつかの高レベルのロジックに従って仮想DOMを返す関数を提供できます。このような関数には、次の署名があります。
const Component = ( props , state , setState , hooks ) {
// Return your Virtual DOM
return div ( ... )
} propsプロパティには、コンポーネントが作成されたときに与えられたプロパティオブジェクトが含まれています。
stateは空のオブジェクト{}に初期化され、 setState({ newState })メソッドを呼び出すことで更新されます。後者はまた、コンポーネントとその子供の更新をトリガーします。
更新を引き起こしたくない場合は、Propertiesをstateオブジェクトに直接割り当てることもできます。
hooksオブジェクトは、コンポーネントライフサイクルメソッドにハンドラーを登録するときに使用できます。
Reactと同様に、 .domコンポーネントにはライフサイクルがあります。
ライフサイクルメソッドにアクセスするには、コンポーネント関数で4番目の引数を使用する必要があります。より具体的には、次のフィールドのいずれかで処理機能をプッシュする必要があります。
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' )速記関数は、 H関数からプロパティとして抽出できます。そのような速記はHとまったく同じように振る舞いますが、タグ名がすでに存在しています。
JavaScriptのミニファイヤーが結果をさらに最適化するのに役立つために、スクリプトの先頭で分解課題を使用することをお勧めします。
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 ) classNameをプロパティとして提供する代わりに、速記のタグメソッドと組み合わせて.className速記を使用できます。
これはdiv({className: 'className'})を呼び出すのと同じであり、関数インターフェイスは上記とまったく同じです。
注:複数の.classをタグに連結することにより、複数のクラスを追加できます。例: div.foo.barはdiv({className: 'foo bar'})と同じです。
プロジェクトの焦点は小さなサイズであるため、正気のチェックが欠けています。これにより、エラーの影響を受けやすくなります。次の警告には非常に注意してください。
プロパティの削除で更新をトリガーすることはできません。代わりに、新しいプロパティを空の値に設定する必要があります。例えば:
// Wrong
R ( div ( { className : 'foo' } ) , document . body ) ;
R ( div ( { } ) , document . body ) ;
// Correct
R ( div ( { className : 'foo' } ) , document . body ) ;
R ( div ( { className : '' } ) , document . body ) ;コンポーネントに$という名前のプロパティを使用してはいけません。そうすることで、プロパティオブジェクトが仮想DOMノードと見なされ、予期しない結果につながります。
// *NEVER* do this!
R ( H ( MyComponent , { $ : 'Foo' } ) , document . body ) K(state, components)
plugin-keyed.min.jsで
keyプロパティに従って、リスト内のコンポーネントの状態が同期されるようにします。これにより、Reactのようなキー付き更新を行うことができます。
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 ) )
} .domに貢献することに興味がありますか?どういたしまして!ガイドラインに従ってください。
npm install
npm test && npm run build && ls -l dotdom.min.js.gz
テストが通過し、 dotdom.min.js.gzのサイズが512バイト以下の場合は、プルリクエストを作成します。それ以外の場合は、スコープを削減するか、512バイトに戻すために別の実装を考えてください。
おそらく、極端なJavaScriptハッキングを行う必要があるため、コードを適切にコメントするようにしてください。 Gudeliensは次のとおりです。
/**
* 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 */
...Apacheライセンス、バージョン2.0に基づいてライセンスされています