浏览 4742 次
锁定老帖子 主题:自创了一套JS的设计模式
精华帖 (0) :: 良好帖 (0) :: 新手帖 (13) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2013-01-09
源码部分使用了John Resig的Simple JavaScript Inheritance 以下是源码部分: define(function(require,exports, module){ var $=require('jquery'); require('../../hashchange/1.3.0/hashchange.js'); var Juicer=require('../../juicer/0.6.4/juicer-debug.js'); var WSUI=$UI={}; WSUI.Classes={}; WSUI.Singleton={}; $UI.setup={}; if(typeof jsContent=="undefined")jsContent={}; jQuery.extend($UI.setup,jsContent); /* Simple JavaScript Inheritance * By John Resig http://ejohn.org/ * MIT Licensed. */ // Inspired by base2 and Prototype var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; // The base Class implementation (does nothing) var Class = function(){}; // Create a new Class that inherits from this class Class.extend = function(prop) { var _super = this.prototype; // Instantiate a base class (but only create the instance, // don't run the init constructor) initializing = true; var prototype = new this(); initializing = false; // Copy the properties over onto the new prototype for (var name in prop) { // Check if we're overwriting an existing function prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function(name, fn){ return function() { var tmp = this._super; // Add a new ._super() method that is the same method // but on the super-class this._super = _super[name]; // The method only need to be bound temporarily, so we // remove it when we're done executing var ret = fn.apply(this, arguments); this._super = tmp; return ret; }; })(name, prop[name]) : prop[name]; } // The dummy class constructor function Class() { // All construction is actually done in the init method if ( !initializing && this.init ) this.init.apply(this, arguments); } // Populate our constructed prototype object Class.prototype = prototype; // Enforce the constructor to be what we expect Class.prototype.constructor = Class; // And make this class extendable Class.extend = arguments.callee; return Class; }; WSUI.Core= Class.extend({ init:function(_opt){ this.observers=[];//增加观察者 this.random=function(length, upper, lower, number){ if( !upper && !lower && !number ){ upper = lower = number = true; } if(!length)length=20; var a = [ ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"], ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"], ["0","1","2","3","4","5","6","7","8","9"] ]; //临时数组 var b = []; //临时字串 var c = ""; b = upper ? b.concat(a[0]) : b; b = lower ? b.concat(a[1]) : b; b = number ? b.concat(a[2]) : b; for (var i=0;i<length;i++){ c += b[ Math.round(Math.random()*(b.length-1)) ]; } return c; }; //每个对象都产生一个随机数作为id this.set('id',this.random()); //判断是否开启调试 if(this.debug ){ this.log=function(log,memo){//l内容,m说明 if(!memo)memo=''; //采用seajs的log替代console.log,避免IE出错 seajs.log(' %s 输出 %s: %o',this.name,memo,log); } }else{ this.log=jQuery.noop; } }, _set:function(para,val){ var _this=this; this[para]=val; //遍历observer表,如果此属性在观察者列表里,则进行匹配 jQuery.each(this.observers,function(i){ if((this['para']==para)&&(this['val']!=val)){//如果参数相等,值有变更,则执行observer函数 this['func'](val);//将变更后的值返回给函数,并执行 //更新observers _this.observers[i]['val']=val; } }) }, set:function(para,val){//设置变量,需要实现BACKBONE的变更检测 var _this=this; if((arguments.length==1)&&(typeof(para)=='object')){//只有一个对象 jQuery.each(para,function(k,i){ _this._set(k,i); }) }else{ this._set(para,val); } return this; }, get:function(para){//获取变量 return this[para]; }, addObserver:function(para,func){//观察者,参考emberjs的观察者模式实现 var _this=this; this.observers.push({ 'para':para, 'val':_this[para], 'func':func }); return this; }, registerSingleton:function(){//标识单例 var root=WSUI.Singleton; //目前先采用同级的方法 root[this.name]=this; }, unregisterSingleton:function(){//删除单例表示 // var root=WSUI.Singleton; // //目前先采用同级的方法 // root[this.name]=this; }, registerClasses:function(_cls,id){//绑定注册表 var root=WSUI.Classes; //目前先采用同级的方法 if(!id){ root[_cls]=this; }else{ if(!root[_cls])root[_cls]={}; root[_cls][id]=this; } }, unregisterClasses:function(_cls){//注销 delete WSUI.Classes[_cls]; }, destroy:function(){ this.set('id',null); //清理IE内存 if(jQuery.browser.msie)CollectGarbage(); } }); WSUI.Model=WSUI.Core.extend({ debug:false, init:function(_opt){ this._super(_opt); this.cache={};//缓存列表 }, //overwrite:如果存在不覆盖,不存在写入 buildCache:function(id,val,overwrite){ if(!overwrite)overwrite=false; if(this.cache[id]){ if(overwrite){ this.cache[id]=val; } }else{ this.cache[id]=val; } }, readCache:function(id){ if(this.cache[id]){ return this.cache[id]; }else{ return undefined; } }, clearCache:function(){ this.cache={}; }, //重新定义remove方法,由于JS的特性,remove只移除本身所用到的对象,但自身还得由外部del destroy:function(){ this._super(); } }); WSUI.View=WSUI.Core.extend({ debug:false, name:'', init:function(_opt){ if(!_opt)_opt={}; this._super(_opt); this.set({ 'el':_opt.el }); this._super(_opt); this.dom=jQuery('<div>',{id:this.id});//考虑到样式全部由模板决定,所以取消view的class,此VIEW只作为容器,标注ID即可 this.get('el').html(this.dom); }, //目前已支持局部渲染 //注:底层框架不关心异步问题 render:function(_opt){ if(!_opt)_opt={}; var option={ data:_opt.data||{}, tpl:_opt.tpl||'<div></div>', node:_opt.node||'', callback:_opt.callback|| $.noop }; var _this=this; if(option.node==''){ _this.dom.html(jQuery(Juicer(option.tpl,option.data)).html()); }else{ _this.dom.find(option.node).html(jQuery(Juicer(option.tpl,option.data)).find(option.node).html()); } //option.callback(); }, destroy:function(){ this._super(); } }); WSUI.Presenter=WSUI.Core.extend({ debug:false, init:function(_opt){ if(!_opt)_opt={}; this._super(_opt); this.set('el',_opt['el']||(function(){seajs.error('target属性必须填写')})()); //如果has_module,则remove原模块 if(this.get('el').attr('has_module')){ WSUI.Classes[this.get('el').attr('has_module')].remove(); } //在target上声明id,方便调用其他模块时执行自动卸载 this.get('el').attr('has_module',this.get('id')); }, destroy:function(){ this._super(); } }); //运用此方法替代new 以实现单例 WSUI.Create=function(_class,_opt){ if(!_opt)_opt={}; if(WSUI.Singleton[_class.prototype.name]){//检测单例列表里是否有此类,如果有,直接返回 return WSUI.Singleton[_class.prototype.name]; }else{ return new _class(_opt); } }; return WSUI; }); 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2013-01-09
以下是具体的使用代码
define(function(require,exports, module){ var WSUI=require('../../../assets/wsui/3.0.0/wsui.js'); var 作者_Template='<div>\n <ul>\n 会什么:<br />\n {@each skillLevel as item,index}\n ${index} 等级${item}\n {@/each}\n </ul>\n\n <ul>\n 不会什么:\n {@each worstSkill as item}\n ${item}\n {@/each}\n </ul>\n\n</div>'; var 作者_Model=WSUI.Model.extend({ name:'作者_Model', init:function(选项){ if(!选项)选项={}; this._super(选项); this.set('个人信息',{ 'skillLevel':{// {skillName:level 1~5} 'html':5, 'css':5, 'javascript':4, 'photoshop':5, '性能优化':4, '搜索引擎优化':4, '设计模式':3, 'UI设计':4, 'UE设计':3 }, 'worstSkill':['后台开发能力','服务器部署维护','专业的单元测试'] }) }, 获取个人信息:function(){ return this.get('个人信息'); } }); var 作者_View=WSUI.View.extend({ name:'作者_View', init:function(选项){ if(!选项)选项={}; this._super(选项); } }); var 作者_Presenter=WSUI.Presenter.extend({ name:'作者_Presenter', init:function(选项){ if(!选项)选项={}; this._super(选项); this.模型层=WSUI.Create(作者_Model); this.表现层=WSUI.Create(作者_View,{ el:this.get('el') }); this.表现层.render({ tpl:作者_Template, data:this.模型层.获取个人信息() }) } }); module.exports=WSUI.Create(作者_Presenter,{ el:$('#个人') }); }); |
|
返回顶楼 | |
发表时间:2013-01-09
最后修改:2013-01-09
代码说明:
line 3:定义模板 line 4~27:定义模型 line 28~34: 定义视图层 line 35~51:定义了主持层,也可以理解为控制层 设计思路 模板HTML:模板只需关心页面HTML及CSS即可 数据模型:数据层只需提供数据,并根据需要做数据缓存,而无需关心表现。 视图层:负责视图本身的JS控件及模板文件的选择。注:视图控件不会涉及到视图以外的部分以及数据的请求 主持层:负责视图的选择、数据模型的选择,当然还包括控件的选择,他所使用的控件与视图层的控件最大差别就是 可以操作视图及模型。 原则上为了将耦合度降到最低~只需主持层决定模型及视图的调用,而视图决定模板的选择,数据层及模板完全可以独立开发。 补充:这套结构有点类似MVC,但个人觉得他并不能列入MVC的设计模式,因为 1、目前位置他的MODEL操作并没有绑定视图层,而需要通过主持层来手动刷新模板。 2、主持层支持多个MODEL的介入。 目前设计的还不是很完善,后期会增加类似BACKBONE的ROUNTER的功能~。 希望大家有什么意见能补充~~~ |
|
返回顶楼 | |
发表时间:2013-01-15
太漫长了!
|
|
返回顶楼 | |
发表时间:2013-03-21
能不能给出一个完整的demo附件啊?能不能!
|
|
返回顶楼 | |