你的位置:首页 > Java教程

[Java教程]构建基础的JavaScript MVC(一)


最近又把《基于MVC的JavaScript web富应用开发》过了一遍....看着自己的年度规划还有好多事没做(哈,要好好把握进度啊),但是也不能留旧账啊,所以还是总结一下啦,该书

对MVC做了基础的介绍,如果想往框架和类库方面探究,可以看看。

一、MVC基础

1、模型

 模型用来存放应用的数据对象;比如一个User模型;
   模型不必知晓试图和控制器的细节;
   模型最应该从应用中解藕;
   当控制器从服务器抓取数据或创建新纪录时,可以将数据包装成模型实例;

例如:        //good case  //封装 & 实例方法  var user = new User('name', 'tel', 'job');  user.destroy();    //bad case  //因为destoryUser不在User的实例中  var user = {name: 'vczero', tel: '132******', job: '前端'};  destoryUser(user);

2、视图

 视图主要由html、css、js模板;
   模板中不应该存在逻辑,除了条件语句之外;

例如:    //render.js  function render(data){    //something to do    //...    view('userinfo', data);  }    //tpl.html  <div>    <span>{{data.name}}</span>    <span>{{data.age}}</span>  </div>

3、控制器

 控制器是视图间的纽带;
   控制器会给视图添加事件监听;

例如:     function userController(){    //....  }    userController.add('#btn', 'click', function(){...});

二、构建类

1、构造函数:第一次实践

  //通过new和构造函数  var User = function(name, nickname){    this.name = name;    this.nickname = nickname;  }    //实例化对象 good case  var user = new User('vczero', '鬼谣');

2、模拟类库

  var Class = function(){    var klass = function(){      this.init.apply(this, arguments);    };    klass.prototype.init = function(){};      return klass;  }    var User = new Class();  //初始化  User.prototype.init = function(){    console.log('------hello world-------');  }  //添加实例函数  User.prototype.show = function(){    console.log('show method');  }  //添加静态函数  User.userCompare = function(){    console.log('这里当然可以使用this比较');  }  var user = new User();    //为了简洁,可以给类的prototype起个别名  //例如User.fn = User.prototype;  //User.fn.add = function(){....}

3、封装:更加清楚的表达 

  //上面的模拟类库表达不是很直观,因此采用新的方式  //增加extend和include方法  var Class = function(){    var klass = function(){      this.init.apply(this, arguments);    };    klass.prototype.init = function(){};        //prototype别名    klass.fn = klass.prototype;        //类别名    klass.fn.parent = klass;        //增加类属性    Klass.extend = function(obj){      var extended = obj.extended;      for(var i in obj){        klass[i] = obj[i];      }      if(extended)extended(klass);    };    //增加实例属性    klass.include = function(obj){      var included = obj.included;      for(var i in obj){        klass.fn[i] = obj[i];      }      if(included) included(klass);    };        return klass;  }    //实例化对象  var User = new Class();  //静态方法  User.extend({    isName: function(){......},    isNum: function(){......}  });  //实例方法  User.include({    add: function(){......},    delete: function(){......}  });

4、基于原型的继承

  var User = function(){};  User.prototype.show = function(){    console.log('----show----');  };    var Student = function(){};  //Student继承了User  Student.prototype = new User();  Student.prototype.study = function(){    console.log('-----study-----');  };    var stu = new Student();  stu.show();  stu.study();

5、给Class增加继承

  var Class = function(parent){    var kalss = function(){      this.init.apply(this, arguments);    };    if(parent){    var subclass = function(){};    subclass.prototype = parent.prototype;    klass.prototype = new subclass();  }    klass.prototype.init = function(){};  klass.fn = klass.prototype;  klass.fn.parent = klass;  //这里可以参考github.com/maccman/super.js  klass._super = klass.__proto__;    //增加类属性    Klass.extend = function(obj){      var extended = obj.extended;      for(var i in obj){        klass[i] = obj[i];      }      if(extended)extended(klass);    };    //增加实例属性    klass.include = function(obj){      var included = obj.included;      for(var i in obj){        klass.fn[i] = obj[i];      }      if(included) included(klass);    };        return klass;  };  

三、事件监听

1、基础事件

  /*  * 事件   *   * */  var Event = {    //添加事件    addEvent: function(el, type, callback, useCapture){      if(el.addEventListener){        el.addEventListener(type, callback, !useCapture);      }else{        el.attachEvent('on' + type, callback);      }      return callback;    },    //删除事件    deleteEvent: function(el, type, callback, useCapture){      if(el.removeEventListener){        el.removeEventListener(type, callback, !useCapture);      }else{        el.detachEvent('on' + type, callback);      }    },    //创建事件    createEvent: function(types){      if(document.createEvent){        return document.createEvent(types);      }else{        return document.createEventObject();      }    },    //触发事件    fireEvent: function(el, type, args, event){      args = args || {};      if(el.dispatchEvent){        event = document.createEvent('HTMLEvents');        event.initEvent(type, true, true);      }else{        event = document.createEventObject();      }          for(var i in args){        if(args.hasOwnProperty(i)){          event[i] = args[i];        }      }      if(el.dispatchEvent){        el.dispatchEvent(event);      }else{        el.fireEvent('on' + type, event);      }    }  };

2、订阅 & 发布

  var PubSub = {    sub: function(event, callback){      var calls = this._callbacks || (this._callbacks = {});      (this._callbacks[event] || (this._callbacks[event])).push(callback);      return this;    },        publish: function(){      var args = Array.prototype.slice.call(arguments, 0);      var ev = args.shift();            var list, calls, i, l;      if(!(calls = this._callbacks)) return this;      if(!(list = this._callback[ev])) return this;            for(i = 0, l = list.length; i < l; i++){        list[i].apply(this, args);      }      return this;    }  };

四、模型

1、模型的构建

  var User = {    records: [],    fetchRemote: function(){...}  };    以上代码有几个优点  (0)子面量表达,那些属性和方法属于哪个对象,清晰明了;  (1)属性保存在User命名空间下,可以减少命名冲突;  (2)同时,我们可以很好的封装代码;  But(世界上最怕的就是but了), 我们需要创建实例对象和实例方法。因此,我们改造:    var User = function(name){    this.name = name || 'vczero';  }    User.prototype.getName = function(){    return this.name;  }

2、ORM(对象关系映射)

ORM可以将模型和数据服务结合在一起,任何模型实例的改变都会发起一个ajax请求到服务器;或者说,将模型实例和HTML元素绑在一起。ORM的基础功能有CRUD数据、合法性校验、监听等。

  ORM可以将模型和数据服务结合在一起,任何模型实例的改变都会发起一个ajax请求到服务器;或者说,  将模型实例和HTML元素绑在一起。ORM的基础功能有CRUD数据、合法性校验、监听等。  1、基于原型的继承(prototype-based)  Object.create传入一个参数,返回新一个新对象(新对象的原型就是传入参数),也即继承于参数对象  if(typeof Object.create !== 'function'){    Object.create = function(o){      function F(){}      F.prototype = o;      return new F();    }  }      现在,可以创建一个Model对象,将用于构建实例:  var Model = {    inherited: function(){},    created: function(){},    prototype: {      init: function(){}    },    //返回一个新对象,这个对象继承于Model    create: function(){      var obj = Object.create(this);      obj.parent = this;      obj.prototype = obj.fn = Object.create(this.prototype);      obj.created();      this.inherited(obj);      return obj;    },    //返回一个新对象,继承于Model.prototype,即Model的一个实例    init: function(){      var instance = Object.create(this.prototype);      instance.parent = this;      instance.init.apply(instance, arguments);      return instance;    }  };    var User = Model.create();  var user = User.init();    2、添加ORM属性  在Jquery中,增加静态属性即类属性是:   $.extend(Model, {     check: function(){...}   });  在Jquery中,增加实例属性是:   $.extend(Model.prototype, {     add: function(){...}   });     为了增加更多的属性到对象中,扩展Model属性,extend是扩展静态属性;include是扩展实例方法:   var Model = {     ...     extend: function(o){       var extended = o.extended;       $.extend(this, o);       if(extended) extended(this);     },     include: function(o){       var included = o.included;       $.extend(this.prototype, o);       if(included) included(this);     }   }     Model.include({     init: function(opts){       this.name = opts.name;     }   });     var User = Model.create();  var user = User.init({name: ''})    3、保存对象  需要能够对对象进行CRUD的操作,因此,增加records.  Model.records = {};  Model.include({    newRecord: true,    create: function(){      this.newRecord = false;      this.parent.records[this.id] = this;    },    destroy: function(){      delete this.parent.records[this.id];    },    update: function(){      this.parent.records[this.id] = this;    },    save: function(){      this.newRecord ? this.create() : this. this.update();    }  });    4、如果需要根据id来索引,可以创建GUID  具体代码参考:https://github.com/vczero/guid/blob/master/guid_js.js  此时,代码可以修改为:  Model.extend({    create: function(){      if(!this.id) this.id = GUID.create();      this.newRecord = false;      this.parent.records[this.id] = this;    }  });  5、提交数据模型到服务器  为了持久化,需要讲数据模型添加到服务器,因此可以增加方法  saveServer: function(url, callback){    //do AJAX  }

--by vczero(http://www.cnblogs.com/vczero/p/mvc_1.html)