绑定到非DOM ui元素

ber*_*tvh 8 fabricjs knockout.js

我正在使用梦幻般的knockout.js将ViewModel属性绑定到DOM.现在,我的部分GUI在canvas元素上呈现.我使用fabric.js在画布上绘制元素.由于这些元素不是dom的一部分(它们是围绕画布绘制方法的包装),我不能使用knockout来绑定它们.不过,我需要在ViewModel中跟踪它们的位置/颜色/标签.

我想我可以为每个结构基元类型创建一个自定义绑定,然后像dom节点一样绑定它们.但是,自定义绑定需要DOM元素作为其第一个参数.其次,我不能(轻松地)以编程方式添加绑定.我需要能够这样做,因为我无法用HTML编写绑定.

我还在考虑这个问题,但我现在有点困惑.有任何想法吗?

RP *_*yer 4

自定义绑定在计算的可观察量内部实现,以便跟踪依赖项并update可以再次触发功能。

听起来对于您的功能来说,您可能需要考虑使用计算的可观察量来跟踪您的对象、访问依赖项并进行任何必要的更新/api 调用。

到目前为止,我还没有使用过 Fabric,但这里将定义一个视图模型来表示一个矩形,并创建一个计算模型,以便在任何值发生变化时不断更新 Fabric 对象。

// create a wrapper around native canvas element (with id="c")
var canvas = new fabric.Canvas('c');

var RectangleViewModel = function (canvas) {
  this.left = ko.observable(100);
  this.top = ko.observable(100);
  this.fill = ko.observable("red");
  this.width = ko.observable(100);
  this.height = ko.observable(100);

  this.rect = new fabric.Rect(this.getParams());
  canvas.add(this.rect);

  this.rectTracker = ko.computed(function () {
     this.rect.set(this.getParams());

     canvas.renderAll();      
  }, this);

};

RectangleViewModel.prototype.getParams = function () {
    return {
        left: +this.left(),
        top: +this.top(),
        fill: this.fill(),
        width: +this.width(),
        height: +this.height()
    };
};

var vm = new RectangleViewModel(canvas);

ko.applyBindings(vm);
Run Code Online (Sandbox Code Playgroud)

另一个简短的想法,如果您宁愿将某些结构/画布调用保留在视图模型之外(我可能会这样做)。您可以创建一个fabric绑定,该绑定接受一系列形状以添加到画布中。您还可以传递一个处理程序,该处理程序检索要传递给它的参数。然后,绑定将创建形状,将其添加到画布,然后创建计算值以在更改时更新形状。就像是:

ko.bindingHandlers.fabric = {
    init: function (element, valueAccessor) {
        var shapes = valueAccessor(),
            canvas = new fabric.Canvas(element);

        ko.utils.arrayForEach(shapes, function (shape) {
            //create the new shape and initialize it
            var newShape = new fabric[shape.type](shape.params());
            canvas.add(newShape);

            //track changes to the shape (dependencies accessed in the params() function
            ko.computed(function () {
                newShape.set(this.params());
                canvas.renderAll();
            }, shape, {
                disposeWhenNodeIsRemoved: element
            });

        });
    }
};
Run Code Online (Sandbox Code Playgroud)

您可以将其放置在画布上,例如:

<canvas data-bind="fabric: [ { type: 'Rect', params: rect.getParams }, { type: 'Rect', params: rect2.getParams } ]"></canvas>
Run Code Online (Sandbox Code Playgroud)

到那时,视图模型可以被大大简化以仅表示矩形的数据。示例在这里: http: //jsfiddle.net/rniemeyer/G6MGm/