好问题。
如果您向对象添加自定义属性,这些对象可能在某种程度上是“特殊的”。似乎对它们进行子类化是一个合理的解决方案。
例如,下面是我们如何子类化一个fabric.Image
到命名图像中。这些图像对象可以有“Gandalf”或“Samwise”等名称。
fabric.NamedImage = fabric.util.createClass(fabric.Image, {
type: 'named-image',
initialize: function(element, options) {
this.callSuper('initialize', element, options);
options && this.set('name', options.name);
},
toObject: function() {
return fabric.util.object.extend(this.callSuper('toObject'), { name: this.name });
}
});
首先,我们给这些对象一个类型。该类型用于loadFromJSON
自动调用fabric.<type>.fromObject
方法。在这种情况下,它将是fabric.NamedImage.fromObject
.
然后我们覆盖initialize
(构造函数)实例方法,在初始化对象时还设置“name”属性(如果给出了该属性)。
然后我们覆盖toObject
实例方法在返回的对象中包含“名称”(这是结构中对象序列化的基石)。
最后,我们还需要实现fabric.NamedImage.fromObject
我之前提到过,所以loadFromJSON
会知道在 JSON 解析期间调用哪个方法:
fabric.NamedImage.fromObject = function(object, callback) {
fabric.util.loadImage(object.src, function(img) {
callback && callback(new fabric.NamedImage(img, object));
});
};
我们在这里加载一个图像(来自“object.src”),然后创建一个实例fabric.NamedImage
出来了。请注意,此时构造函数将已经处理“名称”设置,因为我们之前覆盖了“初始化”方法。
我们还需要指定fabric.NamedImage
是一个异步“类”,这意味着它fromObject
不返回实例,而是将其传递给回调:
fabric.NamedImage.async = true;
现在我们可以尝试一下:
// create image element
var img = document.createElement('img');
img.src = 'https://www.google.com/images/srpr/logo3w.png';
// create an instance of named image
var namedImg = new fabric.NamedImage(img, { name: 'foobar' });
// add it to canvas
canvas.add(namedImg);
// save json
var json = JSON.stringify(canvas);
// clear canvas
canvas.clear();
// and load everything from the same json
canvas.loadFromJSON(json, function() {
// making sure to render canvas at the end
canvas.renderAll();
// and checking if object's "name" is preserved
console.log(canvas.item(0).name);
});