上文提到計划開發的一個支持用戶擴展的開放設計器平台,它基於Html5,純JS,考慮到方便用戶進行引用和擴展,定義成一個單獨的js組件的形式,本文重點就如何設計JS組件做一個詳細說明。
設計組件前,我們先要思考組件如何初始化,首先既然是圖形化的,那就必須用到HTML5的Canvas元素,開發人員先在頁面上建一個canvas作為設計器組件的宿主,在組件$(function(){...})執行時,調用組件的初始化方法(init),然后依據初始化顯示的內容再在畫布上面進行渲染(render)。
第一種組件寫法:全局Javascript 對象法
我們知道Javascript里所有對象定義是以大括號來定義的{}的,那我們visualDesigner.1.0可以定義為:
var visualDesigner = { mode:1, //設計時/運行時 container: "", //容器id content: {}, //內容 init: function (config) { this.container = config.id; this.mode = config.runMode; if (config.content) this.content = JSON.parse(config.content); //默認初始化時加載的內容 this.render(); }, render: function () { if (this.content && this.content.text) { $("#" + this.container).html(this.content.text); } }, save: function () { //保存content }, open: function (content) { //通常保存到本地或數據庫時以字符串形式存在的,故需轉成對象。 if (content) this.content = JSON.parse(content); else console.log("open方法打開的content不能為空"); this.render(); } } var runMode = { designTime: 1, runTime: 2 };
可以這樣調用:
$(function () { visualDesigner.init({ id: "designView", runMode: runMode.designTime, content: "{\"text\":\"hello world\"}" }); })
這種方法最大的問題是所有的屬性或方法都是公有的,如果代碼方法和屬性比較多時,比較難以維護,面向對象設計時一個重要的原則是開放-封閉原則,而這樣的設計完全違背了這個原則。
第二種組件寫法:JQuery組件寫法
jquery組件的寫法第一種是通過標記的形式,比如在容器上標記 data-toggle=“designerView",然后在document.ready時組件函數自動調用初始化(init)
另一種寫法是通過在組件里document.ready或等價的(fucntion(){...})(jQuery)函數里手動調用對象的init初始化,一些jquery插件如bootstrap的組件、jquery.validator等都是基於這種方法。
$(function () { $("#designView").visualDesigner("init", { model: runMode.designTime, content: "{\"text\":\"hello world\"}" }); })
以下為visualDesigner.2.0定義:
+function ($) { "use strict"; // VisualDesigner 公共類定義 // =============================== var VisualDesigner = function (element, options) { this.init(element, options) } if (!paper) throw new Error('VisualDesigner requires paper.js') VisualDesigner.DEFAULTS = $.extend({},{ content: '', color: "red", font_color: "yellow", opacity:0.5 }) VisualDesigner.prototype.init = function (element, options) { this.enabled = true this.$element = $(element) this.htmlCanvas = element instanceof jQuery? element[0] : element; this.options = this.getOptions(options) //初始化設計器代碼 this.canvas = paper.setup(this.htmlCanvas.id); //this.canvas.project.view.viewSize = new paper.Size(this.options.width, this.options.height); this.options = $.extend({ 'raster': 0 }, this.options || {}); this.originalPoint = this.canvas.project.view.center;//保留中心 this.centerPoint = { x: 0, y: 0 }; this.group = new paper.Group(); var fillColor = this.options.color; var fontColor = this.options.font_color; var rect = new paper.Path.Rectangle({ point: [50,50], size: [100,100], radius: 5, strokeWidth: 1, strokeColor: this.options.color, fillColor: this.options.color, opacity: this.node_opacity }); this.group.addChild(rect); } // NOTE: VisualDesigner 原型定義 // ================================ VisualDesigner.prototype.constructor = VisualDesigner VisualDesigner.prototype.getDefaults = function () { return VisualDesigner.DEFAULTS } VisualDesigner.prototype.getOptions = function (options) { options = $.extend({}, this.getDefaults(), this.$element.data(), options) return options; } VisualDesigner.prototype.render = function (content) { //此處為渲染內容的代碼 } VisualDesigner.prototype.open = function (content) { //此處打開操作:清除原來內容,並渲染新內容的代碼 this.render(content); } VisualDesigner.prototype.save = function (saveFunc) { //此處獲取當前內容,並回調保存代碼,回調的參數包含了當前內容 saveFunc(this.getContent()); } VisualDesigner.prototype.hasContent = function () { return this.getTitle() || this.getContent() } VisualDesigner.prototype.getContent = function () { var $e = this.$element var o = this.options return $e.attr('data-content') || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content) } debugger; var old = $.fn.visualDesigner // VisualDesigner 插件定義,擴展jquery函數 // ========================= $.fn.visualDesigner = function (option) { debugger; return new VisualDesigner(this, option); } $.fn.visualDesigner.Constructor = VisualDesigner // visualDesigner 非沖突 // =================== $.fn.visualDesigner.noConflict = function () { $.fn.visualDesigner = old return this } }($); var runMode = { designTime: 1, runTime: 2 };
注意上面代碼的幾個知識點
- +function($){...}($);的寫法和(funtion ($) {}) ($);是一致的,即先定義一個匿名函數,並調用,和var a=function($){}; a($);是等價的。
- jquery通過$.fn來擴展方法,可以通過$.fn.extend({funcName:function(){}});的形式或者$.fn.funcName=function(){};的方法直接賦值。
一旦定義好了方法jquery組件,我們可以通過以下方法實例化:
//html:
<canvas style="height:300px;width:300px;background-color:gray" id="designView"></canvas>
//script:
var view = $("#designView").visualDesigner({ model: runMode.designTime, content: "{\"text\":\"hello world\"}" }); view.open("");
頁面呈現的效果如圖(初始化時畫了一個圓角矩形):
本節js組件就到這里,后續會對javascript的封裝和繼承等再做示例,歡迎繼續關注。
(本文為原創,在引用代碼和文字時請注明出處)
關鍵字:設計器源代碼,Web設計器,工作流設計器,jQuery插件,組態設計器,SCADA系統設計器,流程圖設計,表單設計建模,報表設計,可視化,設計時,運行時,輕量級開放平台。