JavaScript で DOM データ バインディングを実装する
足し算が数学に重要であるのと同様に、データバインディングは現在のアプリケーションにとって重要です。 それなしで重要なアプリケーションを作成するのは非常識に思えます。
データ バインディングに関連する Model-View-Controller パターンは、何百もの子孫を生み出してきた最も基本的なアーキテクチャ パターンの 1つです。
この記事では、JavaScript でのデータ バインディングについて説明し、さまざまなメソッドを共有します。
JavaScript での一方向データ バインディング
存在する JavaScript フレームワークの動機の多くは、JavaScript の認識された欠点から生じています。 ただし、言語としての JavaScript は、フレームワークの必要性が大幅に減少するところまで成長しました。
データ バインディングの概念は非常に基本的なものです。 一方にはデータ モデルがあり、もう一方にはビューと呼ばれることが多いインターフェイスがあります。
目的は、一部のデータをビュー上の何かにバインド
して、データが変更されるとビューも変更されるようにすることです。 これは、読み取り専用データによく見られます。
モデルとビューが変更された場合にのみ、一方向のデータ バインディングが発生します。
最も単純なように見えますが、プロパティの JavaScript ゲッターとセッターにフックする必要があるため、一方向のデータ バインディングは達成するのが最も難しい可能性があります。 Object.defineProperty
は、JavaScript で長い間使用されてきました。
このメソッドを使用すると、開発者はオブジェクトのカスタム getter および setter を構築し、既存のものを置き換えることができます。 たとえば、この関数は次のコードで使用され、以前に指定されたプロパティのゲッターとセッターを変更します。
function Binding(b) {
_this = this this.element = b.element this.value =
b.object[b.property] this.attribute = b.attribute this.valueGetter =
function() {
return _this.value;
} this.valueSetter =
function(val) {
_this.value = val
_this.element[_this.attribute] = val
}
Object.defineProperty(
b.object, b.property,
{get: this.valueGetter, set: this.valueSetter});
b.object[b.property] = this.value;
this.element[this.attribute] = this.value
}
コードを見てみましょう。シャドウ プロパティを作成して値を Binding
オブジェクトに格納し、defineProperty
を使用してプロパティのゲッターとセッターを設定します。 等号 (=
) を使用してプロパティが設定されるたびに、setter メソッドが呼び出されるようになりました。
最後に、関数はプロパティと DOM 要素を指定された値に設定します。 この リンク から、このコードの動作を確認できます。
JavaScript での限定的な双方向データ バインディング
ビューまたはモデルが変更されると、双方向のデータ バインディングが発生します。 双方向バインディングは、同じ基本コードを使用して構築できます。
バインドには、DOM フィードバックを受け取るためにリッスンするイベントが必要です。 関数 addEventListener
が呼び出される場所に注意してください。
これにより、渡された要素にイベント リスナーが追加されます。 イベント ハンドラーは、イベントが呼び出されるたびに、要素にデータ バインドされたオブジェクト値のシャドウ コピーを設定します。
モデルを変更すると、DOM 要素も更新されます。
function Binding(b) {
_this = this this.element = b.element this.value =
b.object[b.property] this.attribute = b.attribute this.valueGetter =
function() {
return _this.value;
} this.valueSetter =
function(val) {
_this.value = val
_this.element[_this.attribute] = val
}
if (b.event) {
this.element.addEventListener(b.event, function(event) {
_this.value = _this.element[_this.attribute]
})
}
Object.defineProperty(
b.object, b.property, {get: this.valueGetter, set: this.valueSetter});
b.object[b.property] = this.value;
this.element[this.attribute] = this.value
}
この リンク から、このコードの動作を確認できます。
ただし、このコードは、要素と属性に対して 1つの一方向または双方向のデータ バインディングのみを許可するという点で、比較的制限的です。
JavaScript での双方向データ バインディングの改善
プロパティを 1つ以上の項目に関連付けることができるようにすることは、双方向のデータ バインディングへの優れたアプローチです。 これは、値が変更された場合 (DOM イベントが呼び出された場合やモデルが変更された場合)、データ バインディングが DOM 上の多数の項目を更新できることを意味します。
また、新しく導入された addBinding
メソッドにも注目してください。 これにより、イベントとのバインディングに新しいコンポーネントを追加できるようになりました。
これらは、配列 elementBindings
に追加されます。 セッター メソッドは、新しい値が設定されてプロパティが変更されると、elementBindings
配列全体を反復処理します。
また、addBinding
の実行時に event
オプションを省略して、一方向のデータ バインディングを作成するために使用することもできます。
function Binding(b) {
_this = this this.elementBindings = [] this.value =
b.object[b.property] this.valueGetter =
function() {
return _this.value;
} this.valueSetter =
function(val) {
_this.value = val
for (var i = 0; i < _this.elementBindings.length; i++) {
var binding = _this.elementBindings[i]
binding.element[binding.attribute] = val
}
} this.addBinding =
function(element, attribute, event) {
var binding = { element: element, attribute: attribute } if (event) {
element.addEventListener(event, function(event) {
_this.valueSetter(element[attribute]);
})
binding.event = event
}
this.elementBindings.push(binding)
element[attribute] = _this.value
return _this
}
Object.defineProperty(
b.object, b.property,
{get: this.valueGetter, set: this.valueSetter});
b.object[b.property] = this.value;
}
この リンク から、このコードの動作を確認できます。
この実装の方が優れていますが、まだやるべきことがたくさんあります。 たとえば、データの検証、テンプレート化、配列のサポート、カスタム UI セッターまたは UI フォーマッター、およびその他の多くの制限はありません。
これらすべてを組み合わせると、フレームワーク
という用語が形成され始め、それらの多くが存在します。 ただし、このような単純なスクリプトは、多くのニーズに対応するデータ バインディングに必要なものを十分に処理できます。