問題のデモについては、このペンを参照してください(チュートリアルのスライドショーに基づく)。「次へ」と「前へ」の矢印をクリックすると、imgIndex
口ひげは正しく更新されますが、 などの式の口ひげ<p>{{ curImageCaption() }}</p>
は値がいつ変更されるかを認識しません。
つまり、オブジェクトは、式が再評価されると口ひげの値が変わるように変更されますが、ractive はそれを認識していないようです。書き込みアダプターを除いて、これを機能させる方法はありますか? マジックモードの仕組みを誤解していますか? 興味深いことに、イベント ハンドラー内で明示的に呼び出してもractive.update()
、ractive は応答しません。
新しい情報で更新
さらにいじった後、私はそれを機能させるこのハックを思いつきました。ハックは、変更することです。たとえば、単純なプリミティブを口ひげの表現<p>{{ curImageCaption() }}</p>
に<p>{{ curImageCaption(imgIndex) }}</p>
追加して、ractive が正しく監視する方法を理解するようにします。
今何が起こっているかはわかりますが、変化するプリミティブを含む口ひげ式に引数を明示的に追加する必要があると、別のドメイン オブジェクトを持つ目的の多くが無効になります。つまり、ractive を念頭に置いてドメイン オブジェクトをコーディングしています。プリミティブの変更を使用して、変更を通知するための一種の基本的な pub/sub メカニズムを使用します。
カスタム オブジェクトに実際の pub/sub メカニズムを作成する必要があり、それが ractive で明示的にサブスクライブされるのは問題ありません。問題は、OPで指摘したように、 ractive が を介して変更を通知された場合ractive.update()
でも、偽の引数ハックを使用しない限り、口ひげを再計算する必要があることをまだ認識していないことです。そのため、すべてを機能させるためにどのコールバック ractive を登録する必要があるかは明確ではありません。
これを行うのに十分なほどractiveの内部動作を理解していませんが、必要なのは、それらを直接_deps
操作し、式の再計算を手動でトリガーする機能であると思います。これが正しいと思われる場合は、それを達成する方法の例をいただければ幸いです。
UPDATE 2 -- まともな解決策
アイデアは、ECMA5 プロパティを使用してカスタム ドメイン オブジェクトを装飾し、使用したいが、ractive テンプレート内では機能しない既存のメソッドに委任するプロパティを提供することです。プロパティ、おと、うまくいきます。
<p>{{ curImageCaption() }}</p>
そのため、単純に を記述する代わりに、次の<p>{{ imageCaption }}</p>
ようにカスタム ドメイン オブジェクトを装飾します。
Object.defineProperty(mySlideshow, "imageCaption", {
configurable: true,
get: function() { return this.curImageCaption() },
set: function() { }
});
この装飾は、私のデモでは少し冗長ですが、オブジェクトの新しい ractive フレンドリなプロパティ名をオブジェクトの既存のメソッドの名前にマッピングし、上記のボイラープレートを処理するオブジェクトを受け入れるヘルパー メソッドを作成することで、簡単にスリム化できます。 .
注: この方法の欠点の 1 つはractive.update()
、イベント ハンドラーで手動で呼び出す必要があることです。それを回避する方法があれば知りたいです。また、そうでない場合、これによってどの程度のパフォーマンス ヒットが発生するのでしょうか? それは、ractive の外科的アップデートの目的全体を無効にしますか?
Update 3 -- より適切な解決策はありますか?
このペンはさらに別のアプローチを採用しており、汎用ディスパッチャ オブジェクト ( を実装するオブジェクトnotify()
) を介してカスタム ドメイン モデルを ractive にリンクします。これまでのアプローチの中でこれが私のお気に入りだと思います....
これは公式のractive アダプターに似ていますが、オブジェクトをラップするのではなく、非公式の ractive アダプターをドメイン オブジェクトに渡すために DI を使用しています。一見、「非アクティブにコーディング」しているように見えるかもしれませんが、実際にはこれは部分的にしか当てはまりません。別のフレームワークを使用していたとしても、何らかの通知メカニズムを使用して変更をビュー モデルにブロードキャストし、ビューがそれに反応できるようにする必要があります。この DI アプローチは、公式の ractive アダプターよりもボイラープレートを必要としないようですが、これを確実に知るのに十分なほどよく理解していません。公式のアダプターほど完全に一般的なソリューションでもありません。
後世のためのペンからのコード
HTML
<div id='output'></div>
<script id='template' type='text/ractive'>
<div class='slideshow'>
<div class='main'>
<a class='prev' on-tap='prev'><span>«</span></a>
<div class='main-image' style='background-image: url({{ curImageSrc() }});'></div>
<a class='next' on-tap='next'><span>»</span></a>
</div>
<div class='caption'>
<p>{{ curImageCaption() }}</p>
<p>Image index: {{ imgIndex }} </p>
</div>
</div>
</script>
JS
// Fix JS modular arithmetic to always return positive numbers
function mod(m, n) { return ((m%n)+n)%n; }
function SlideshowViewModel(imageData) {
var self = this;
self.imgIndex = 0;
self.next = function() { self.setLegalIndex(self.imgIndex+1); }
self.prev = function() { self.setLegalIndex(self.imgIndex-1); }
self.curImage = function() { return imageData[self.imgIndex]; }
self.curImageSrc = function() { return self.curImage().src; }
self.curImageCaption = function() { return self.curImage().caption; }
self.setLegalIndex = function(newIndex) { self.imgIndex = mod(newIndex, imageData.length); }
}
var mySlideshow = new SlideshowViewModel(
[
{ src: imgPath('problem.gif'), caption: 'Trying to work out a problem after the 5th hour' },
{ src: imgPath('css.gif'), caption: 'Trying to fix someone else\'s CSS' },
{ src: imgPath('ie.gif'), caption: 'Testing interface on Internet Explorer' },
{ src: imgPath('w3c.gif'), caption: 'Trying to code to W3C standards' },
{ src: imgPath('build.gif'), caption: 'Visiting the guy that wrote the build scripts' },
{ src: imgPath('test.gif'), caption: 'I don\'t need to test that. What can possibly go wrong?' }
]
);
var ractive = new Ractive({
el: '#output',
template: '#template',
data: mySlideshow,
magic: true
});
ractive.on( 'next', function(event) {
ractive.data.next();
});
ractive.on( 'prev', function(event) {
ractive.data.prev();
});
function imgPath(name) { return 'http://learn.ractivejs.org/files/gifs/' + name; }