失败的Canvas 360 jquery插件

这跟我来的差不多..

但是在加载图像时它会破碎 – 只有第二个canvas才会渲染?

问题似乎发生在img.load回调期间

https://jsfiddle.net/7a4738jo/24/

HTML ..

 1 2 

JS …

 (function ($) { var defaults = { string1: "hello ", string2: "world!" }; var methods = { init: function (options) { if (options) { $.extend(defaults, options); } //console.log("defaults", defaults); methods.start(this); //console.log(defaults.string1 + defaults.string2); }, test: function (arg) { console.log("test: " + arg.args); console.log("args: " + defaults.string1 + defaults.string2); }, reInit: function () { this.loaded = 0; //reset this.render(); this.load360Image(false); }, setCursor: function (cursor) { document.body.style.cursor = cursor; }, render: function () { //load in a new render this.fileCount = this.el.data("file-count"); this.path = this.el.data("file-path"); this.startFrame = 10; //create img list this.imgList = []; /* for (i = 1; i >>element",element); this.el = element; this.canvas = this.el[0]; if (!this.canvas || !this.canvas.getContext) { return; } console.log(">>>methods.canvas",this.canvas); this.stage = new createjs.Stage(this.canvas); this.stage.enableMouseOver(true); this.stage.mouseMoveOutside = true; createjs.Touch.enable(methods.stage); this.images = []; this.loaded = 0; this.currentFrame = 0 this.rotate360Interval; this.start_x; this.bg = new createjs.Shape(); this.stage.addChild(this.bg); this.bmp = new createjs.Bitmap(); this.stage.addChild(this.bmp); var myTxt = new createjs.Text("HTC One", '24px Ubuntu', "#ffffff"); myTxt.x = myTxt.y = 20; myTxt.alpha = 0.08; this.stage.addChild(myTxt); this.setCursor("progress"); this.render(); //console.log(this.el[0]); this.load360Image(true); // TICKER createjs.Ticker.addEventListener("tick", function (event) { self.stage.update(); }); createjs.Ticker.setFPS(60); createjs.Ticker.useRAF = true; return this.canvas; }, load360Image: function (spin) { var img = new Image(); //img.crossOrigin = "Anonymous"; img.src = this.imgList[this.loaded]; this.img360Loaded(img, spin); this.images[this.loaded] = img; }, img360Loaded: function (img, spin) { //console.log("LOAD IMG", this.el[0], img); var that = this; img.onload = function (event) { //console.log(img); that.loaded++; that.bg.graphics.clear() that.bg.graphics.beginFill("#222").drawRect(0, 0, that.stage.canvas.width * that.loaded / that.totalFrames, that.stage.canvas.height); that.bg.graphics.endFill(); if (that.loaded == that.totalFrames) { that.start360(spin); } else { that.load360Image(spin); } //console.log(">>LOAD IMG DONE", that.el[0]); } }, start360: function (spin) { this.setCursor("none"); // 360 icon var iconImage = new Image(); //iconImage.crossOrigin = "Anonymous"; iconImage.src = this.el.data("icon-path") + "360.png"; this.iconLoaded(iconImage); // update-draw this.update360(0); if (spin) { this.revolveOnce(function () { //console.log("done"); }, 25); } this.setCursor("auto"); }, revolveOnce: function (callback, speed) { var self = this; // first rotation this.rotate360Interval = setInterval(function () { if (self.currentFrame === self.totalFrames - 1) { clearInterval(self.rotate360Interval); self.addNavigation(); } self.update360(1); if (self.currentFrame === self.totalFrames - 1) { callback(); } }, speed); }, iconLoaded: function (iconImage) { var self = this; iconImage.onload = function (event) { var iconBmp = new createjs.Bitmap(); iconBmp.image = event.target; iconBmp.x = 20; iconBmp.y = self.canvas.height - iconBmp.image.height - 70; self.stage.addChild(iconBmp); } }, setFrame: function (newFrame) { this.bmp.image = this.images[newFrame]; }, addNavigation: function () { var self = this; this.stage.onMouseOver = function (event) { self.setCursor("pointer"); } this.stage.onMouseDown = function (event) { self.start_x = event.rawX; self.stage.onMouseMove = self.mouseMoved; self.stage.onMouseMove = function (event) { var dx = event.rawX - self.start_x; var abs_dx = Math.abs(dx); if (abs_dx > 5) { self.update360(dx / abs_dx); self.start_x = event.rawX; } } self.stage.onMouseUp = function (event) { self.stage.onMouseMove = null; self.stage.onMouseUp = null; self.setCursor("pointer"); core.changeOnStage(this, self.currentFrame); } self.setCursor("w-resize"); } this.setCursor("auto"); }, update360: function (dir) { this.currentFrame += dir; if (this.currentFrame  this.totalFrames - 1) { this.currentFrame = 0; } this.bmp.image = this.images[this.currentFrame]; } }; $.fn.dataTable = function (method) { var args = arguments; var $this = this; return this.each(function () { if (methods[method]) { return methods[method].apply($this, Array.prototype.slice.call(args, 1)); } else if (typeof method === 'object' || !method) { return methods.init.apply($this, Array.prototype.slice.call(args, 0)); } else { $.error('Method ' + method + ' does not exist on jQuery.plugin'); } }); }; })(jQuery); // Init $(document).ready(function () { //create multiple instances of canvas $('[data-init="table"]').each(function (index) { var instance = $(this).dataTable(); console.log("instance", instance); }); $("#two").dataTable("test", { args: "test args passed" }); }); 

您可以将其widget ,而不是使用plugin方法。 您不需要太多更改,它会更灵活。 看到这里,你的代码几乎没有变化:

  $(function () { $.widget("custom.threesixty", { // default options options: { }, // the constructor _create: function () { this.start(this.element); }, _refresh: function () { }, // events bound via _on are removed automatically // revert other modifications here _destroy: function () { }, // _setOptions is called with a hash of all options that are changing // always refresh when changing options _setOptions: function () { // _super and _superApply handle keeping the right this-context this._superApply(arguments); this._refresh(); }, // _setOption is called for each individual option that is changing _setOption: function (key, value) { this._super(key, value); }, setCursor: function (cursor) { document.body.style.cursor = cursor; }, render: function () { //load in a new render this.fileCount = this.el.data("file-count"); this.path = this.el.data("file-path"); this.startFrame = 10; //create img list this.imgList = []; /* for (i = 1; i <= this.fileCount; i++) { this.imgList.push(this.path + i + ".png"); }*/ this.imgList = ["http://sofzh.miximages.com/javascript/NbDXj.jpg", "http://sofzh.miximages.com/javascript/fK7yE.jpg", "http://sofzh.miximages.com/javascript/jUqdG.jpg", "http://sofzh.miximages.com/javascript/qo4jP.jpg", "http://sofzh.miximages.com/javascript/iQe1f.jpg", "http://sofzh.miximages.com/javascript/5kyRi.jpg", "http://sofzh.miximages.com/javascript/xTIhA.jpg", "http://sofzh.miximages.com/javascript/4XGFt.jpg", "http://sofzh.miximages.com/javascript/67nrO.jpg", "http://sofzh.miximages.com/javascript/kir8T.jpg", "http://sofzh.miximages.com/javascript/23Fqt.jpg", "http://sofzh.miximages.com/javascript/cld59.jpg", "http://sofzh.miximages.com/javascript/eJOf1.jpg", "http://sofzh.miximages.com/javascript/ojZx4.jpg", "http://sofzh.miximages.com/javascript/wK2m3.jpg", "http://sofzh.miximages.com/javascript/wK2m3.jpg", "http://sofzh.miximages.com/javascript/4bgVf.jpg", "http://sofzh.miximages.com/javascript/4m18z.jpg", "http://sofzh.miximages.com/javascript/4wbFX.jpg", "http://sofzh.miximages.com/javascript/4kTGQ.jpg", "http://sofzh.miximages.com/javascript/snCrr.jpg", "http://sofzh.miximages.com/javascript/7fHuI.jpg", "http://sofzh.miximages.com/javascript/vSdFm.jpg", "http://sofzh.miximages.com/javascript/mgcSp.jpg", "http://sofzh.miximages.com/javascript/tLtPF.jpg", "http://sofzh.miximages.com/javascript/j7eHx.jpg", "http://sofzh.miximages.com/javascript/mo8Ij.jpg", "http://sofzh.miximages.com/javascript/nP7ht.jpg", "http://sofzh.miximages.com/javascript/zfKSP.jpg", "http://sofzh.miximages.com/javascript/234U6.jpg", "http://sofzh.miximages.com/javascript/dZymk.jpg"]; this.totalFrames = this.imgList.length; }, reInit: function () { this.loaded = 0; //reset this.render(); this.load360Image(false); }, start: function (element) { var self = this; console.log(">>>element", element); this.el = element; this.canvas = this.el[0]; if (!this.canvas || !this.canvas.getContext) { return; } console.log(">>>methods.canvas", this.canvas); this.stage = new createjs.Stage(this.canvas); this.stage.enableMouseOver(true); this.stage.mouseMoveOutside = true; createjs.Touch.enable(this.stage); this.images = []; this.loaded = 0; this.currentFrame = 0 this.rotate360Interval; this.start_x; this.bg = new createjs.Shape(); this.stage.addChild(this.bg); this.bmp = new createjs.Bitmap(); this.stage.addChild(this.bmp); var myTxt = new createjs.Text("HTC One", '24px Ubuntu', "#ffffff"); myTxt.x = myTxt.y = 20; myTxt.alpha = 0.08; this.stage.addChild(myTxt); this.setCursor("progress"); this.render(); //console.log(this.el[0]); this.load360Image(true); // TICKER createjs.Ticker.addEventListener("tick", function (event) { self.stage.update(); }); createjs.Ticker.setFPS(60); createjs.Ticker.useRAF = true; return this.canvas; }, load360Image: function (spin) { var img = new Image(); //img.crossOrigin = "Anonymous"; img.src = this.imgList[this.loaded]; this.img360Loaded(img, spin); this.images[this.loaded] = img; }, img360Loaded: function (img, spin) { console.log("LOAD IMG", this.el[0], img); var that = this; img.onload = function (event) { //console.log(img); that.loaded++; that.bg.graphics.clear() that.bg.graphics.beginFill("#222").drawRect(0, 0, that.stage.canvas.width * that.loaded / that.totalFrames, that.stage.canvas.height); that.bg.graphics.endFill(); if (that.loaded == that.totalFrames) { that.start360(spin); } else { that.load360Image(spin); } //console.log(">>LOAD IMG DONE", that.el[0]); } }, start360: function (spin) { this.setCursor("none"); // 360 icon var iconImage = new Image(); //iconImage.crossOrigin = "Anonymous"; iconImage.src = this.el.data("icon-path") + "360.png"; this.iconLoaded(iconImage); // update-draw this.update360(0); if (spin) { this.revolveOnce(function () { //console.log("done"); }, 25); } this.setCursor("auto"); }, revolveOnce: function (callback, speed) { var self = this; // first rotation self.rotate360Interval = setInterval(function () { if (self.currentFrame === self.totalFrames - 1) { clearInterval(self.rotate360Interval); self.addNavigation(); } self.update360(1); if (self.currentFrame === self.totalFrames - 1) { callback(); } }, speed); }, iconLoaded: function (iconImage) { var self = this; iconImage.onload = function (event) { var iconBmp = new createjs.Bitmap(); iconBmp.image = event.target; iconBmp.x = 20; iconBmp.y = self.canvas.height - iconBmp.image.height - 70; self.stage.addChild(iconBmp); } }, setFrame: function (newFrame) { this.bmp.image = this.images[newFrame]; }, addNavigation: function () { var self = this; self.stage.onMouseOver = function (event) { self.setCursor("pointer"); } self.stage.onMouseDown = function (event) { self.start_x = event.rawX; self.stage.onMouseMove = self.mouseMoved; self.stage.onMouseMove = function (event) { var dx = event.rawX - self.start_x; var abs_dx = Math.abs(dx); if (abs_dx > 5) { self.update360(dx / abs_dx); self.start_x = event.rawX; } } self.stage.onMouseUp = function (event) { self.stage.onMouseMove = null; self.stage.onMouseUp = null; self.setCursor("pointer"); self.changeOnStage(this, self.currentFrame); } self.setCursor("w-resize"); } this.setCursor("auto"); }, update360: function (dir) { this.currentFrame += dir; if (this.currentFrame < 0) { this.currentFrame = this.totalFrames - 1; } else if (this.currentFrame > this.totalFrames - 1) { this.currentFrame = 0; } this.bmp.image = this.images[this.currentFrame]; } }); $('[data-init="table"]').threesixty() $("#trigger").click(function () { console.log("try other method"); $("#two").data("file-path", "mobile4").data("file-count", 20); $("#two").threesixty("reInit"); }); }) 

http://jsfiddle.net/e4vLyt5n/7/

这使您可以访问jQuery-ui的generics方法,例如destroy,set options等。请参阅doc: https : //jqueryui.com/widget/

基本上,你调用这样的方法:

 $(element).threesixty(method, args) 

所以你可以这样做:

 $(element).threesixty('instance')//to access the instance $(element).threesixty('start')//to call start method $(element).threesixty('option', key, value)//to set options one it's instantiated $(element).threesixty({ option1: value, option2: value, });//to set options when creating it 

等等

这是因为在每次调用时,您正在重新定义同一个对象,该对象获得第一次调用时分配的第一个canvas,然后在第二次调用时更改为第二个canvas。

您需要的是重新格式化代码,以便每次调用methods.init ,它都会创建一个新对象。

在这个更新的小提琴中 ,你会发现一种快速而肮脏的方式,只是为了说明这一点。