3

我一直在尝试创建一个自定义绑定来更新浮动图表,它似乎在它第一次加载时可以工作,但是当我浏览它时它退出了。

这是场景,我在一个页面上有一个列表视图(这是在 jQuery Mobile 中),带有小图的缩略图,图旁边是一个滑块,它绑定到同一视图模型的属性,导致图指向被重新计算。当您单击其中一个列表项时,它会移动到显示更大版本的图表的另一个页面,并允许您通过在文本框中键入来更改值(稍后,您将能够直接单击图表) . 绑定看起来像这样:

    ko.bindingHandlers["plot"] = {
        init: function (element, valueAccessor, allBindingsAccessor) {
            var qe = $(element);
            var page = qe.closest("div[data-role='page']");
            page.bind("pageshow", function () {
                ko.bindingHandlers["plot"].update(element, valueAccessor);
            });
        },
        update: function (element, valueAccessor, allBindingsAccessor) {
            var qe = $(element);
            var page = qe.closest("div[data-role='page']");
            var curr = $.mobile.activePage;
            var val = ko.utils.unwrapObservable(valueAccessor());
            var data = val.plotData();
            if(data && page.prop("id") == curr.prop("id")) {
                var marker = val.markerData();
                var opt = val.chartOptions();
                opt.yaxis.show = opt.xaxis.show = !qe.hasClass("graphThumb");
                marker.points.radius = opt.yaxis.show ? 5 : 3.5;
                $.plot(qe, [
                    data, 
                    marker
                ], opt);
            }
        }
    };

处理程序将其init设置为在页面显示上绘制图形,因为 flot 在绘制到不可见时无法正常工作div。更新将检查当前显示的页面是否与绑定的页面相同,并根据需要重新绘制图形。

对于列表视图中的图形,它们会立即通过该update方法绘制并正常工作。但是,对于最初隐藏的页面,绘制图形的功能会触发,图形绘制,但更新将不再起作用。然后,更糟糕的是,当您返回初始页面时,绑定到pageshow事件的函数会触发,重新绘制图形,但现在它们也退出了更新。

视图模型看起来像这样:

var viewModel = (function () {
    this.current = ko.observable(0);
    this.plotData = ko.computed(function () {
        var points = [];
        // a bunch of calculations that depend on the value of current of this and other viewModels in a collection
        return points;
    }
}

我可以在计算中设置一个断点plotData并查看它是否正确更新。只是这些更新不会触发绑定处理程序。

HTML 绑定看起来像这样:

<!-- the first, visible page -->
<div data-role="page" id="index">
    <ul data-role="listview" data-bind="foreach: factors">
        <li data-bind="attr: {id: listId}">
            <a data-bind="attr: {href: idLink}">
                <div class="graphThumb" data-bind="plot: $data"></div>
            </a>
        </li>
     </ul>
</div>
<!-- hidden details pages -->
<!-- ko foreach: factors -->
<div data-role="page" data-bind="attr: { id: id }"> 
    <div class="graphPlaceHolder" data-bind="plot: $data"></div>
</div>
<!-- /ko -->

更新:我稍微改变了我的绑定,因为我意识到我可以调用update事件pageshow处理程序,这简化了事情,但没有解决问题。似乎这样做不会使淘汰赛更新它对绑定的依赖项。

更新:另一个更新,分配val.plotData()给一个变量没有工作,也没有包括在我的if声明中。但是,我有另一个计算的 observable,它取决于current父视图模型的值和另一个属性,我可以检索并添加到我的if有效语句中!但是,我的解决方案可能具体到通常有用。简短的故事是,淘汰赛将在每次更新时重新评估绑定的依赖关系,因此您需要确保它正在评估重要的东西,而不考虑任何条件逻辑,否则它将停止更新。

4

1 回答 1

0

所以我可以总结一下这个问题并将其标记为已回答,我将简要总结一下我的经验。

自定义绑定的实现与 Knockout 中的计算属性相同(根据 KO 文档),计算属性所做的一件事是在每次执行它们时重新评估它们依赖的属性。这意味着,如果您在计算属性(或自定义绑定)中有条件,则只有在实际执行的条件分支中访问的属性才会通过敲除来监视更改。因此,例如,如果您有这样的属性:

var myComputedProperty = ko.computed(function() {
    if(this.myBool()) {
        $("#someElement").text(this.foo());
    }
    else {
        $("#someElement").text(this.bar());
    }
});

KO 将跟踪 的值myBool并在属性更改时重新计算,但是,如果myBool为 true,它也会跟踪foo,如果myBool为 false,它也会跟踪bar,但不会同时跟踪两者 - 因为它不需要到。大多数时候这工作得很好。

在我的情况下,它失败了,因为我有一个不属于视图模型的条件(因此不可观察),我需要它来跟踪视图模型属性,无论条件评估为真还是错误的。所以我有一些看起来像这样的东西:

if(page.prop("id") == curr.prop("id")) {
    $("#someElement").text(this.foo());
}

这里比较的是id绑定所在的页面和$.mobile.activePagejQuery Mobile 提供的页面之间的比较(并且,显然不可观察)。如果这些id匹配,则淘汰赛将在foo更改时更新绑定。但是,如果他们不这样做,那么淘汰赛将失去对的依赖foo,即使id在稍后的某个时间匹配,它也会失去依赖并且不会在foo更改时重新评估。

解决此问题的方法是确保无论条件如何,都对需要跟踪的任何属性进行评估。所以,这样的事情应该解决一般情况:

if(this.foo() && page.prop("id") == curr.prop("id")) {
    $("#someElement").text(this.foo());
}

至于我为什么需要这个条件,是因为 flot 在尝试将图形绘制到不可见的 div 时会变得非常困惑,所以当它不是当前页面时,我需要跳过绘制图形。

于 2012-12-20T18:50:18.757 回答