组件的多个实例
现在,我们利用写好的 LabeledSlider 组件来重构我们的 BMI 小程序:
出现 bug 了,我们拖动任意一个滑块,都会引起另一个滑块的变化,这显然就表明了两个滑块实例出现了 冲突。原因不难找到,在滑块组件的 Intent 中,我们把 css class 为 .slider
的滑块全部进行了事件绑定:
function intent(DOMSource) {
const change$ = DOMSource.select('.slider').events('input').map(evt => evt.target.value);
return change$;
}
对此,我们首先能够想到的解决思路是,在组件实例化时,为不同的实例进行不同的标识,比如指定不同的 css class。并且,在组件实例化时,传入绑定了该 class 对应事件的 DOM source:
function main(sources) {
const weightProps$ = Rx.Observable.of({
label: 'Weight',
unit: 'kg',
min: 40,
max: 150,
init: 70
});
const weightSinks = LabeledSlider({
DOM: sources.DOM.select('.weight'),
props: weightProps$
});
const weightVTree$ = weightSinks.DOM.map(vtree => {
vtree.properties.className += ' weight';
return vtree;
});
const heightProps$ = Rx.Observable.of({
label: 'Height',
unit: 'cm',
min: 140,
max: 220,
init: 170
});
const heightSinks = LabeledSlider({
DOM: sources.DOM.select('.height'),
props: heightProps$
});
const heightVTree$ = heightSinks.DOM.map(vtree => {
vtree.properties.className += ' height';
return vtree;
});
const vtree$ = Rx.Observable.combineLatest(
weightSinks.DOM, heightSinks.DOM,
(weightVTree, heightVTree) => {
return div([
weightVTree,
heightVTree
]);
}
);
return {
DOM: vtree$
};
}
别忘了在 Intent 和组件的绑定位置解耦:
function intent(DOMSource) {
const change$ = DOMSource.events('input').map(evt => evt.target.value);
return change$;
}
现在,bug 就修复了: