在Knockout.JS中更新视图模型后调用视图函数
我使用优秀的Cycle.js插件创建了一个简单的内容旋转器,它从我的Knockout.js视图模型属性(本例中为appViewModel.mediaPlayer)获取内容: e、 g 这是使用JQuery Tmpl在视图中呈现的在Knockout.JS中更新视图模型后调用视图函数,knockout.js,Knockout.js,我使用优秀的Cycle.js插件创建了一个简单的内容旋转器,它从我的Knockout.js视图模型属性(本例中为appViewModel.mediaPlayer)获取内容: e、 g 这是使用JQuery Tmpl在视图中呈现的 <script id="mediaPlayerTemplate" type="text/template"> <img src=${url} /> </script> <div class="adCo
<script id="mediaPlayerTemplate" type="text/template">
<img src=${url} />
</script>
<div class="adContainer" data-bind="template: {name: 'mediaPlayerTemplate', foreach: mediaPlayer}">
</div>
这很好,但是当我更新视图模型媒体播放器内容时,cycle插件停止工作…这不是问题,因为对cycle()的简单调用将再次启动它
但是,我的问题是,调用cycle()更新视图的最佳位置在哪里?我想我可以订阅mediaPlayer的更改,只需在需要时调用该方法,但是这意味着我必须将JQuery元素/视图逻辑放在视图模型中,这感觉是错误的(也许我是想太纯粹了!)
简而言之,在视图模型不知道视图函数的情况下,如何从视图模型触发视图中的函数?在Silverlight/WPF中,XAML中的触发器可以实现这一点,但我不确定如何使用Knockout.JS实现相同的分离。我认为最好使用BindingHandler实现这一点,这还允许在重新呈现内容时正确处理插件 您的示例(它将在5秒后更改循环): HTML:
<script id="mediaPlayerTemplate" type="text/template">
<img src=${url} />
</script>
<div data-bind="template: {name: 'mediaPlayerTemplate', foreach: mediaPlayer}, cycle: { fx: 'fade', timeout: 1000, speed: 500 }, cycleLinked: mediaPlayer">
</div>
ko.bindingHandlers.cycle = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
$element = $(element);
var options = ko.utils.unwrapObservable(valueAccessor()) || {};
//console.log('cycle_init');
var _starting = false;
var _cycle = function() {
if(_starting) return;
_starting = true;
//console.log('cycle_create');
$element.hide();
setTimeout(function() { $(element).cycle(options); $element.show(); _starting = false; }, 0);
};
var subscription = allBindingsAccessor().cycleLinked.subscribe(_cycle);
//handle disposal
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
//console.log('cycle_destroy');
$element.cycle("destroy");
subscription.dispose();
});
_cycle();
}
};
var testData = [{
url: "http://cloud.github.com/downloads/malsup/cycle/beach1.jpg"},
{
url: "http://cloud.github.com/downloads/malsup/cycle/beach2.jpg"}];
var appViewModel = {
mediaPlayer: new ko.observableArray(testData)
};
ko.applyBindings(appViewModel);
setTimeout(function() {
appViewModel.mediaPlayer.push({url: "http://cloud.github.com/downloads/malsup/cycle/beach3.jpg"});
appViewModel.mediaPlayer.push({url: "http://cloud.github.com/downloads/malsup/cycle/beach4.jpg"});
}, 5000);
<script id="mediaPlayerTemplate" type="text/template">
<img src=${url} />
</script>
<div data-bind="template: {name: 'mediaPlayerTemplate', foreach: mediaPlayer}, cycle: { fx: 'fade', timeout: 1000, speed: 500 }, cycleLinked: mediaPlayer">
</div>
ko.bindingHandlers.cycle = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
$element = $(element);
var options = ko.utils.unwrapObservable(valueAccessor()) || {};
//console.log('cycle_init');
var _starting = false;
var _cycle = function() {
if(_starting) return;
_starting = true;
//console.log('cycle_create');
$element.hide();
setTimeout(function() { $(element).cycle(options); $element.show(); _starting = false; }, 0);
};
var subscription = allBindingsAccessor().cycleLinked.subscribe(_cycle);
//handle disposal
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
//console.log('cycle_destroy');
$element.cycle("destroy");
subscription.dispose();
});
_cycle();
}
};
var testData = [{
url: "http://cloud.github.com/downloads/malsup/cycle/beach1.jpg"},
{
url: "http://cloud.github.com/downloads/malsup/cycle/beach2.jpg"}];
var appViewModel = {
mediaPlayer: new ko.observableArray(testData)
};
ko.applyBindings(appViewModel);
setTimeout(function() {
appViewModel.mediaPlayer.push({url: "http://cloud.github.com/downloads/malsup/cycle/beach3.jpg"});
appViewModel.mediaPlayer.push({url: "http://cloud.github.com/downloads/malsup/cycle/beach4.jpg"});
}, 5000);