1 "use strict";2
3 //------------------华丽的分割线--------------------- //
4
5 //@description 正式的声明Dalmatian框架的命名空间
6 var Dalmatian = Dalmatian ||{};7
8 //@description 定义默认的template方法来自于underscore
9 Dalmatian.template =_.template;10 Dalmatian.View =_.inherit({11 //@description 构造函数入口
12 initialize: function(options) {13 this._initialize();14 this.handleOptions(options);15 this._initRoot();16
17 },18
19 _initRoot: function() {20 //根据html生成的dom包装对象
21 //有一种场景是用户的view本身就是一个只有一个包裹器的结构,他不想要多余的包裹器
22 this.root = $(this.defaultContainerTemplate);23 this.root.attr('id', this.viewid);24 },25
26 //@description 设置默认属性
27 _initialize: function() {28
29 var DEFAULT_CONTAINER_TEMPLATE = '';30
31 //@description view状态机
32 //this.statusSet = {};
33
34 this.defaultContainerTemplate =DEFAULT_CONTAINER_TEMPLATE;35
36 //@override
37 //@description template集合,根据status做template的map
38 //@example
39 //{ 0: '
40 //this.templateSet = {};
41
42 this.viewid = _.uniqueId('dalmatian-view-');43
44 },45
46 //@description 操作构造函数传入操作
47 handleOptions: function(options) {48 //@description 从形参中获取key和value绑定在this上
49 if (_.isObject(options)) _.extend(this, options);50
51 },52
53 //@description 通过模板和数据渲染具体的View
54 //@param status {enum} View的状态参数
55 //@param data {object} 匹配View的数据格式的具体数据
56 //@param callback {functiion} 执行完成之后的回调
57 render: function(status, data, callback) {58
59 var templateSelected = this.templateSet[status];60 if(templateSelected) {61
62 //@description 渲染view
63 var templateFn =Dalmatian.template(templateSelected);64 this.html =templateFn(data);65
66 //这里减少一次js编译
67 //this.root.html('');
68 //this.root.append(this.html);
69
70 this.currentStatus =status;71
72 _.callmethod(callback, this);73
74 return this.html;75
76 }77 },78
79 //@override
80 //@description 可以被复写,当status和data分别发生变化时候
81 //@param status {enum} view的状态值
82 //@param data {object} viewmodel的数据
83 update: function(status, data) {84
85 if (!this.currentStatus || this.currentStatus !==status) {86 return this.render(status, data);87 }88
89 //@override
90 //@description 可复写部分,当数据发生变化但是状态没有发生变化时,页面仅仅变化的可以是局部显示
91 //可以通过获取this.html进行修改
92 _.callmethod(this.onUpdate, this, data);93 }94 });95
96 Dalmatian.Adapter =_.inherit({97
98 //@description 构造函数入口
99 initialize: function(options) {100 this._initialize();101 this.handleOptions(options);102
103 },104
105 //@description 设置默认属性
106 _initialize: function() {107 this.observers =[];108 //this.viewmodel = {};
109 this.datamodel ={};110 },111
112 //@description 操作构造函数传入操作
113 handleOptions: function(options) {114 //@description 从形参中获取key和value绑定在this上
115 if (_.isObject(options)) _.extend(this, options);116 },117
118 //@override
119 //@description 设置
120 format: function(datamodel) {121 returndatamodel;122 },123
124 getViewModel: function() {125 return this.format(this.datamodel);126 },127
128 registerObserver: function(viewcontroller) {129 //@description 检查队列中如果没有viewcontroller,从队列尾部推入
130 if (!_.contains(this.observers, viewcontroller)) {131 this.observers.push(viewcontroller);132 }133 },134
135 unregisterObserver: function(viewcontroller) {136 //@description 从observers的队列中剔除viewcontroller
137 this.observers = _.without(this.observers, viewcontroller);138 },139
140 //统一设置所有观察者的状态,因为对应观察者也许根本不具备相关状态,所以这里需要处理
141 //setStatus: function (status) {
142 //_.each(this.observers, function (viewcontroller) {
143 //if (_.isObject(viewcontroller))
144 //viewcontroller.setViewStatus(status);
145 //});
146 //},
147
148 notifyDataChanged: function() {149 //@description 通知所有注册的观察者被观察者的数据发生变化
150 var data = this.getViewModel();151 _.each(this.observers, function(viewcontroller) {152 if(_.isObject(viewcontroller))153 _.callmethod(viewcontroller.update, viewcontroller, [data]);154 });155 }156 });157
158 Dalmatian.ViewController =_.inherit({159
160 _initialize: function() {161
162 //用户设置的容器选择器,或者dom结构
163 this.container;164 //根元素
165 this.$el;166
167 //一定会出现
168 this.view;169 //可能会出现
170 this.adapter;171 //初始化的时候便需要设置view的状态,否则会渲染失败,这里给一个默认值
172 this.viewstatus = 'init';173
174 },175
176 //@description 构造函数入口
177 initialize: function(options) {178 this._initialize();179 this.handleOptions(options);180 this._handleAdapter();181 this.create();182 },183
184 //处理dataAdpter中的datamodel,为其注入view的默认容器数据
185 _handleAdapter: function() {186 //不存在就不予理睬
187 if (!this.adapter) return;188 this.adapter.registerObserver(this);189 },190
191 //@description 操作构造函数传入操作
192 handleOptions: function(options) {193 if (!options) return;194
195 this._verify(options);196
197 //@description 从形参中获取key和value绑定在this上
198 if (_.isObject(options)) _.extend(this, options);199 },200
201 setViewStatus: function(status) {202 this.viewstatus =status;203 },204
205 //@description 验证参数
206 _verify: function(options) {207 //这个underscore方法新框架在报错
208 //if (!_.property('view')(options) && (!this.view)) throw Error('view必须在实例化的时候传入ViewController');
209 if (options.view && (!this.view)) throw Error('view必须在实例化的时候传入ViewController');210 },211
212 //@description 当数据发生变化时调用onViewUpdate,如果onViewUpdate方法不存在的话,直接调用render方法重绘
213 update: function(data) {214
215 //_.callmethod(this.hide, this);
216
217 if (this.onViewUpdate) {218 _.callmethod(this.onViewUpdate, this, [data]);219 return;220 }221 this.render();222
223 //_.callmethod(this.show, this);
224 },225
226 /**227 * @override228 */
229 render: function() {230 //@notation 这个方法需要被复写
231 this.view.render(this.viewstatus, this.adapter && this.adapter.getViewModel());232 this.view.root.html(this.view.html);233 },234
235 _create: function() {236 this.render();237
238 //render 结束后构建好根元素dom结构
239 this.view.root.html(this.view.html);240 this.$el = this.view.root;241 },242
243 create: function() {244
245 //l_wang这块不是很明白
246 //是否检查映射关系,不存在则recreate,但是在这里dom结构未必在document上
247 //if (!$('#' + this.view.viewid)[0]) {
248 //return _.callmethod(this.recreate, this);
249 //}
250
251 //@notation 在create方法调用前后设置onViewBeforeCreate和onViewAfterCreate两个回调
252 _.wrapmethod(this._create, 'onViewBeforeCreate', 'onViewAfterCreate', this);253
254 },255
256 /**257 * @description 如果进入create判断是否需要update一下页面,sync view和viewcontroller的数据258 */
259 _recreate: function() {260 this.update();261 },262
263 recreate: function() {264 _.wrapmethod(this._recreate, 'onViewBeforeRecreate', 'onViewAfterRecreate', this);265 },266
267 //事件注册点
268 bindEvents: function(events) {269 if (!(events || (events = _.result(this, 'events')))) return this;270 this.unBindEvents();271
272 //@description 解析event参数的正则
273 var delegateEventSplitter = /^(\S+)\s*(.*)$/;274 varkey, method, match, eventName, selector;275
276 //注意,此处做简单的字符串数据解析即可,不做实际业务
277 for (key inevents) {278 method =events[key];279 if (!_.isFunction(method)) method = this[events[key]];280 if (!method) continue;281
282 match =key.match(delegateEventSplitter);283 eventName = match[1], selector = match[2];284 method = _.bind(method, this);285 eventName += '.delegateEvents' + this.view.viewid;286
287 if (selector === '') {288 this.$el.on(eventName, method);289 } else{290 this.$el.on(eventName, selector, method);291 }292 }293
294 return this;295 },296
297 //取消所有事件
298 unBindEvents: function() {299 this.$el.off('.delegateEvents' + this.view.viewid);300 return this;301 },302
303 _show: function() {304 this.bindEvents();305 $(this.container).append(this.$el);306 this.$el.show();307 },308
309 show: function() {310 _.wrapmethod(this._show, 'onViewBeforeShow', 'onViewAfterShow', this);311 },312
313 _hide: function() {314 this.forze();315 this.$el.hide();316 },317
318 hide: function() {319 _.wrapmethod(this._hide, 'onViewBeforeHide', 'onViewAfterHide', this);320 },321
322 _forze: function() {323 this.unBindEvents();324 },325
326 forze: function() {327 _.wrapmethod(this._forze, 'onViewBeforeForzen', 'onViewAfterForzen', this);328 },329
330 _destory: function() {331 this.unBindEvents();332 this.$el.remove();333 //delete this;
334 },335
336 destory: function() {337 _.wrapmethod(this._destory, 'onViewBeforeDestory', 'onViewAfterDestory', this);338 }339 });