上文提到计划开发的一个支持用户扩展的开放设计器平台,它基于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;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系统设计器,流程图设计,表单设计建模,报表设计,可视化,设计时,运行时,轻量级开放平台。