前言
本来是说周末研究一下单页应用来着,先是想发出来可以监督自己学习下去,结果谁知道这个水很深,我连着就赔了一个周末进去,到尽头还没搞完。。。
这次这个框架并不是我一个字写出来的,而是参考了同事的框架,我师傅(http://www.cnblogs.com/aaronjs/)说得好:
传承总比再造好,于是便有了这次的demo,其实就是吸收精华啊!!!
到今天有了一个大概的样子,可以拿出来看看了。其中的Model与localstorege相关也加上了,但是暂时没有用得到的场景。
这个代码后面点应该会持续更新,到我认为比较合适的阶段就会放出来了。。。。 于是我们继续吧!
整体思路
我们先来构思下整个框架的构成(这里参照了同事的框架):
依赖库
① requireJS
② jquery
③ underscore.js
PS:本来还想用backbone的,想下还是算了,研究性目的,不要搞的过于复杂吧
程序流程
基本结构我是这么思考的:
① 我们在网页中输入URL后便进入Index,以requireJS加载主框架APP
② APP.js做一些初始化操作,其主要功能便是观察hash变化(URL变化)
若是改变(初始化进入、或者想去其他页面),便根据规则获取URL相关信息,初始化新的VIEW,进行显示,并将URL压人HASH。
③ 实现VIEW类,其具有基本几个事件(onCreate、onLoad、onRender、onHide)
一个VIEW可以对应其HTML模板(可以0个或者多个)
④ 事件操作使用jquery的吧
PS:暂时这个样子吧,我们边写边改,看最后能做到什么样子,这里还是画个图
于是,我们开始辛苦的基础实现吧,毕竟我们现在还神马都米有!!!
基础实现之继承
其实,我们是面向对象的,若是不面向对象应该会被喷吧,于是我们来一起完成一个基础的继承类吧:
复制代码
1 var b = {};//base
2 var slice = [].slice;
3
4 b.Class = function (supClass, childAttr) {
5 //若是传了第一个类,便继承之;否则实现新类
6 if (typeof supClass === 'object') {
7 childAttr = supClass;
8 supClass = function () { };
9 }
10
11 //定义我们创建的类12 var newClass = function () {
13 this._propertys_();
14 this.init.apply(this, arguments);
15 };
16 newClass.prototype = new supClass();
17
18 var supInit = newClass.prototype.init || function () { };
19 var childInit = childAttr.init || function () { };
20 var _supAttr = newClass.prototype._propertys_ || function () { };
21 var _childAttr = childAttr._propertys_ || function () { };
22
23 for (var k in childAttr) {
24 //_propertys_中作为私有属性
25 childAttr.hasOwnProperty(k) && (newClass.prototype[k] = childAttr[k]);
26 }
27
28 //继承的属性有可能重写init方法
29 if (arguments.length && arguments[0].prototype && arguments[0].prototype.init === supInit) {
30 //重写新建类,初始化方法,传入其继承类的init方法
31 newClass.prototype.init = function () {
32 var scope = this;
33 var args = [function () {
34 supInit.apply(scope, arguments);
35 } ];
36 childInit.apply(scope, args.concat(slice.call(arguments)));
37 };
38 }
39
40 //内部属性赋值
41 newClass.prototype._propertys_ = function () {
42 _supAttr.call(this);
43 _childAttr.call(this);
44 };
45
46 //成员属性
47 for (var k in supClass) {
48 supClass.hasOwnProperty(k) && (newClass[k] = supClass[k]);
49 }
50 return newClass;
51 };
复制代码
代码还是很好理解的:
PS:我们这个框架建立的所有类,都会经过他!!!
可以传递两个两个参数:需要继承的类,新建类的一些参数,这里我们来稍微走一下这个流程:
一个参数
① 我们先初始化一个新的类newClass,并且实例化他,他就会调用本身的两个方法:
this._propertys_() 用于实例化本身属性 this.init.apply(this, arguments) init为我们定义的,每个类都会调用的初始化方法
② 让我们新建的类(newClass)继承自我们传入的类
③ 初始化四个变量,显然这种情况他们都是空函数
④ 将传入的子属性的值给予新建类(newClass),这里只有一个参数便忽略吧
⑤ 29行,由于我们的类继承自supClass,所以这里是满足条件的,我们看看他里面干了些什么:
他重新定义了,我们创建类的init函数(我们说过他在自身属性初始化完毕后会执行)。
这里我们为他的参数新增了一个方法,也就是父类的init方法,只不过其this指向为子类。
复制代码
newClass.prototype.init = function () {
var scope = this;
var args = [function () {
supInit.apply(scope, arguments);
} ];
childInit.apply(scope, args.concat(slice.call(arguments)));
};
复制代码
⑥ 41行,大家注意_propertys_这个函数,他是用于我们为自身属性赋值的,等下我们举个例子
⑦ 最后将父类的成员对象赋给子类(因为我们知道成员是不会被继承的)
⑧ 返回新建类,流程结束
情况我这里不多做介绍,我们再说下两个参数的情况就好。
两个参数
我们这种场景用的也很多,第一个参数为要继承的类,第二个参数为新建类的一些初始化信息,我们来走一次流程吧:
① 传入两个参数,要继承的类;新建类的一些属性和原型方法
② 12行同样初始化我们的新类,我们实例化时,首先会执行_propertys_方法为自身赋值,然后执行初始化方法(可以传递参数哦,参数是new时候传递的):
var newClass = function () {
this._propertys_();
this.init.apply(this, arguments);//此处的参数请注意
};
③ 让新类继承自传入的类,此时我们的newClass.prototype其实就拥有很多方法了,包括init与_propertys_
④ 18-21行,初始化四个后面会用到的函数,各位自己注意其意图
⑤ 23-26行,将将传入的子属性对象,赋予newClass,_propertys_也作为原型对象了
⑥ 29-38行,将父类的init作为参数传递给子类的init,由子类决定是不是要执行
⑦ 最后的就不多说了
好了,到此各位应该了解他的作用了,我们来一个简单的例子吧:
简单例子
实现一个父类Bird(鸟类),及其子类Chicken(鸡)Duck(鸭)
首先,我们来看鸟类都能呼吸,都有名字与年龄,所以我们这么干:
复制代码
1 var Bird = new b.Class({
2 //作为自身属性将被调用,里面必须采用this.XX的方式书写
3 _propertys_: function () {
4 this.name = '鸟类';
5 this.age = 0;
6 },
7 //一定会被执行的初始化方法
8 init: function () {
9 alert('一定会执行');
10 },
11 //原型方法
12 breathe: function () {
13 alert('我能呼吸');
14 }
15 });
16
17 var b = new Bird({des: '测试init方法是否能捕获参数'});
18
19 var s = '';
复制代码
这里我们的init自动执行了,并且,其会用到传入的参数!!!
这是我们得到的鸟类实例。
好了,我们来实例化一个鸡的类,并且他拥有嚎叫打鸣的本领,与性别的特征
复制代码
1 var Chicken = new b.Class(Bird, {
2 _propertys_: function () {
3 this.sex = '公';
4 },
5 //一定会被执行的初始化方法
6 init: function () {
7 alert('我是一只鸡');
8 },
9 //原型方法
10 howl: function () {
11 alert('我能打鸣');
12 }
13 });
复制代码
这里,父类的init会执行,子类的init会执行,而且,子类的init函数会默认带上父类的init方法
init: function (superInit) {
alert('我是一只鸡');
},
PS:虽说父类一定会执行,但是若是在此调用父类的superInit方法的话,this指向是子类哦!!!
好了,这个家伙结束,我们进入下一个核心VIEW
基础实现之视图
视图(View)是我们框架的第二个核心,我们来看看到底可能会有哪些view呢?
① 核心之,页面VIEW
这是最重要的view,他应该包含整个页面的逻辑,从初始化到最后的展示,事件绑定等应该一应俱全
② 各个级别组件,弹出层,提示层,遮盖层......
这些都应该是view,但是,先不管那么多,我们来实现我们的核心吧!!!
思考过程
此处使用backbone的视图到变得简单了,我们来简单思考下我们页面视图形成的流程吧:
① 用户第一次进入界面,访问index,由main导向app,app获得url,获取其相关参数(list)
② app根据list实例化view,view调用自身init方法,慢慢开始构建页面,并会触发各个流程
PS:在此我认为每个页面view应该统一继承一个父类,于是我们来尝试性试试吧
第一版
复制代码
1 b.AbstractView = b.Class({
2 //基本view应该具有的属性
3 _propertys_: function () {
4 this.id = (new Date()).getTime(); //唯一pageID
5 this.rootBox = $('body'); //视图容器
6 this.root = $('<div/>'); //视图的根元素,可进行设置
7 this.header = null;
8 this.footer = null;
9 this.template = '';//可能的模板
10 this.isCreated = false;//是否创建完毕
11 this.status = b.AbstractView.STATE_NOTCREATE;//当前状态
12 },
13 init: function () {
14 },
15 //定义将要用到的事件,其中元素选取都会以root为标准,所以使用内部提供函数吧
16 events: {
17 'selector,eventType': 'func'
18 },
19 //默认属性
20 attrs: {
21 },
22 //获取视图元素
23 find: function (selector) {
24 return this.root.find(selector);
25 },
26 //创建dom
27 create: function (opts) {
28 if(!this.isCreated && this.status != b.AbstractView.STATE_ONCREATE) {
29 var attr = opts && opts.attr;
30 var html = this.createHtml();
31 this.initRoot(attr);//初始化root
32 this.hide();
33 this.rootBox.append(this.root);
34 this.root.html(html);
35 this.trigger('onCreate');//触发正在创建事件,其实这里都创建完了
36 this.status = b.AbstractView.STATE_ONCREATE;
37 this.isCreated = true;
38 this.bindEvent();
39 }
40 },
41 //呈现/渲染视图
42 show: function (callback) {
43 if(this.status == b.AbstractView.STATE_ONSHOW) {
44 return;
45 }
46 this.create();
47 this.root.show();
48 this.trigger('onShow');
49 this.status = b.AbstractView.STATE_ONSHOW
50 callback && (typeof callback == 'function') && callback.call(this);
51 this.trigger('onLoad');
52 },
53 //隐藏dom
54 hide: function (callback) {
55 if(!this.root || this.status == b.AbstractView.STATE_ONHIDE) {
56 return;
57 }
58 this.root.hide();
59 this.trigger('onHide');
60 this.status = b.AbstractView.STATE_ONHIDE;
61 callback && (typeof callback == 'function') && callback();
62 },
63 //事件绑定
64 bindEvent: function () {
65 var events = this.events;
66 for(var k in events) {
67 var sec_type = k.replace(/\s/i, '').split(',');
68 var func = events[k];
69 if(sec_type &&sec_type.length == 2 && typeof func == 'function') {
70 var selector = sec_type[0];
71 var type = sec_type[1];
72 var scope = this;
73 this.find(selector).on(type, function () {
74 func.call(scope, $(this));
75 })
76 }
77 }
78 },
79 //此处可以配合模板与相关参数组成html
80 //解析模板也放到此处
81 createHtml: function () {
82 throw new Error('请重新定义createHtml方法');
83 },
84 initRoot: function () {
85 var attr = this.attrs;
86 if(!attr) {
87 return;
88 }
89 for(var k in attr) {
90 if(k == 'className') {
91 this.root.attr('class', attr[k]);
92 }else {
93 this.root.attr(k, attr[k]);
94 }
95 }
96 this.root.attr('id', this.id);
97 },
98 //触发事件
99 trigger: function (k, args) {
100 var event = this[k];
101 args = args || [];
102 if(event && typeof event == 'function') {
103 event.apply(this, args)
104 }
105 },
106 setRootBox: function (dom) {
107 this.rootBox = dom;
108 },
109 setAttr: function (k, v) {
110 this.root.attr(k, v);
111 },
112 getAttr: function (k) {
113 return this.root.attr(k);
114 },
115 setCss: function (k, v) {
116 this.root.css(k, v);
117 },
118 getCss: function (k) {
119 return this.root.css(k);
120 },
121 //dom创建后执行
122 onCreate: function () {
123
124 },
125 //dom创建后数据加载时执行,用于加载后执行我们的逻辑
126 onLoad: function () {
127
128 },
129 //dom创建后,未显示
130 onShow: function () {
131
132 },
133 //dom隐藏前
134 onHide: function () {
135
136 }
137 });
138
139 //组件状态,未创建
140 b.AbstractView.STATE_NOTCREATE = 'notCreate';
141 //组件状态,已创建但未显示
142 b.AbstractView.STATE_ONCREATE = 'onCreate';
143 //组件状态,已显示
144 b.AbstractView.STATE_ONSHOW = 'onShow';
145 //组件状态,已隐藏
146 b.AbstractView.STATE_ONHIDE = 'onHide';
复制代码
代码注释写的很详细了,我这里就不多说了,我们来用一个例子试一试:
复制代码
1 <!DOCTYPE html>
2 <html xmlns="http://www.w3.org/1999/xhtml">
3 <head>
4 <meta charset="utf-8" />
5 <title></title>
6 <script src="res/libs/jquery.js" type="text/javascript"></script>
7 <script src="res/test/c.base.js" type="text/javascript"></script>
8 </head>
9 <body>
10
11 </body>
12 <script type="text/javascript">
13 var PageView = b.Class(b.AbstractView, {
14 _propertys_: function () {
15 this.template = '我是叶小钗';
16 },
17 init: function (superInit) {
18 console.log(superInit);
19 console.log('init');
20 },
21 createHtml: function () {
22 var htm = [
23 '<header>标题</header>',
24 '<div class="main">',
25 '<input type="text" id="txt" />',
26 '<input type="button" id="bt" value="点击我" />',
27 this.template,
28 '</div>',
29 '<footer>页尾</footer>'
30 ].join('');
31 return htm;
32 },
33 attrs: {
34 'data-id': 'test',
35 className: 'yexiaoc'
36 },
37 events: {
38 '#bt,click': function (el) {
39 var txt = this.find('#txt');
40 alert(txt.val())
41 }
42 },
43 onCreate: function () {
44 console.log('onCreate');
45 },
46 //dom创建后数据加载时执行,用于加载后执行我们的逻辑
47 onLoad: function () {
48 console.log('onLoad');
49 },
50 //dom创建后,未显示
51 onShow: function () {
52 console.log('onShow');
53 },
54 //dom隐藏前
55 onHide: function () {
56 console.log('onHide');
57 }
58 });
59 var view = new PageView();
60 view.show();
61 var s = '';
62 </script>
63 </html>
复制代码
初步实现我们的期望
继承之实现APP
我们这里APP要干的事情,与其说担任MVC中控制器的角色,不如说他就是充当了一下路由选择的角色,根据不同的URL导向不同的view,并且会管理hash。
由于我们会处理request请求,压入hash以达到后退功能有效,所以这里先来实现一个hash类吧
实现Hash对象
先来一个辅助函数,用于计算某个字符在数组的位置:
复制代码
1 var indexOf = function (k, arr) {
2 if (!arr) {
3 return -1;
4 }
5 //若是对象本身便居然indexof,便使用自身的,比如字符串
6 if (arr.indexOf) {
7 return arr.indexOf(k);
8 }
9 for (var i = 0, len = arr.length; i < len; i++) {
10 if (arr[i] == k) {
11 return i;
12 }
13 }
14 return -1;
15 };
复制代码
PS:这个hash的实现不算太好,后面也许会改动
复制代码
1 b.Hash = b.Class({
2 _propertys_: function () {
3 this.keys = [];
4 this.values = [];
5 },
6 init: function (obj) {
7 (typeof obj == 'object') || (obj = {}); //???
8 for (var k in obj) {
9 if (obj.hasOwnProperty(k)) {
10 this.keys.push(k);
11 this.values.push(obj[k]);
12 }
13 }
14 },
15 length: function () {
16 return this.keys.length;
17 },
18 getItem: function (k) {
19 var index = indexOf(k, this.keys);
20 if (index < 0) {
21 return null;
22 }
23 return this.keys[index];
24 },
25 getKey: function (i) {
26 return this.keys[i];
27 },
28 getValue: function (i) {
29 return this.values[i];
30 },
31 add: function (k, v) {
32 return this.push(k, v);
33 },
34 del: function (k) {
35 var index = indexOf(k, this.keys);
36 return this.delByIndex(index);
37 },
38 delByIndex: function (index) {
39 if (index < 0) return this;
40 this.keys.splice(index, 1);
41 this.vaules.splice(index, 1);
42 return this;
43 },
44 //移除栈顶hash,并返回
45 pop: function () {
46 if (!this.keys.length) return null;
47 this.keys.pop();
48 return this.values.pop();
49 },
50 push: function (k, v, order) {
51 if (typeof k == 'object' && !v) {
52 for (var i in k) {
53 if (k.hasOwnProperty(i)) {
54 this.push(i, k[i], order);
55 }
56 }
57 } else {
58 var index = indexOf(k, this.keys);
59 if (index < 0 || order) {
60 if (order) this.del(k);
61 this.keys.push[k];
62 this.values.push[v];
63 } else {
64 this.values[index] = v;
65 }
66 }
67 },
68 //查找hash表,返回key
69 indexOf: function (v) {
70 var index = indexOf(v, this.vaules);
71 if (index >= 0) {
72 return this.keys[index];
73 }
74 return -1;
75 },
76 each: function (handler) {
77 if (typeof handler == 'function') {
78 for (var i = 0, len = this.length(); i < len; i++) {
79 handler.call(this, this.keys[i], this.vaules[i]);
80 }
81 }
82 },
83 getObj: function () {
84 var obj = {};
85 for (var i = 0, len = this.length(); i < len; i++) {
86 obj[this.keys[i]] = this.values[i];
87 }
88 return obj;
89 }
90 });
复制代码
此hash对象基本就是数组的写照,各位可以对照着看,于是我们继续我们的app
app雏形
复制代码
1 var Application = new b.Class({
2 _propertys_: function () {
3 var scope = this;
4 this.webRoot = ''; //应用跟目录
5 this.head = $('head');
6 this.body = $('body');
7 this.viewRoot = 'views/'; //视图所在目录
8 this.defaultView = 'index'; //默认加载视图
9
10 this.request; //请求对象
11 this.viewPath; //当前请求视图路径,解析request得出
12 this.mainFrame; //主框架
13 this.viewPort; //视图框架
14 this.stateDom; //状态栏
15
16 this.views = new b.Hash(); //views保存浏览器存储的hash
17 this.curView; //当前视图
18 this.interface = {}; //提供给视图访问的接口,暂时不管
19 this.history = []; //历史记录
20
21 // this.stopListening = false;//是否开启监听
22
23 this.onHashChange = function () {
24 scope.history.push(window.location.href);
25 var url = decodeURIComponent(window.location.hash.replace(/^#+/i, '')).toLowerCase();
26 scope._onHashChange(url);
27 };
28
29 this.lastHash = '';
30 this.lastFullHash = '';
31 this.isChangeHash = false; //hash是否发生变化
32 },
33 init: function (opts) {
34 //为属性赋值
35 opts = opts || {};
36 for (var k in opts) {
37 this[k] = opts[k];
38 }
39 this.createViewPort();
40 this.bindEvent(); //事件绑定
41 },
42
43 //创建app页面基本框架,此处不能使用id,因为。。。
44 createViewPort: function () {
45 var htm = [
46 '<div class="main-frame">',
47 '<div class="main-viewport"></div>',
48 '<div class="main-state"></div>',
49 '</div>'
50 ].join('');
51 this.mainframe = $(htm);
52 this.viewport = this.mainframe.find('.main-viewport');
53 this.statedom = this.mainframe.find('.main-state');
54 var body = $('body');
55 body.html('');
56 body.append(this.mainframe);
57 },
58 //!!!!!!非常重要哦!!!!!!
59 bindEvent: function () {
60 var scope = this;
61 //暂时不使用requireJS
62 // requirejs.onError = function () {};
63 $(window).bind('hashchange', this.onHashChange);
64 },
65 _onHashChange: function (url) {
66 url = url.replace(/^#+/i, '');
67 var req = this.parseHash(url);
68
69 this.request = req;
70 this.viewPath = this.viewPath || this.defaultView;
71 this.loadView(this.viewPath); //!!!重要的视图加载
72 },
73 //该方法慢慢看吧。。。
74 parseHash: function (hash) {
75 var fullhash = hash,
76 hash = hash.replace(/([^\|]*)(?:\|.*)?$/img, '$1'),
77 h = /^([^?&|]*)(.*)?$/i.exec(hash),
78 vp = h[1] ? h[1].split('!') : [],
79 viewpath = (vp.shift() || '').replace(/(^\/+|\/+$)/i, ''),
80 path = vp.length ? vp.join('!').replace(/(^\/+|\/+$)/i, '').split('/') : [],
81 q = (h[2] || '').replace(/^\?*/i, '').split('&'),
82 query = {}, y;
83 this.isChangeHash = !!(!this.lastHash && fullhash === this.lashFullHash) || !!(this.lastHash && this.lastHash !== hash);
84 if (q) {
85 for (var i = 0; i < q.length; i++) {
86 if (q[i]) {
87 y = q[i].split('=');
88 y[1] ? (query[y[0]] = y[1]) : (query[y[0]] = true);
89 }
90 }
91 }
92
93 this.lastHash = hash;
94 this.lashFullHash = fullhash;
95 return {
96 viewpath: viewpath,
97 path: path,
98 query: query,
99 root: location.pathname + location.search
100 };
101 },
102 //!!!非常重要
103 loadView: function (viewPath) {
104 var id = viewPath;
105 var scope = this;
106 //此处本来应该判断是否已经有该视图,但是我们暂时不管,我们只要加载了相关视图就算成功
107 /*
108 一些操作
109 */
110
111 //此处应该加载我们的js文件
112 $.getScript(this.buildUrl(viewPath), function () {
113 var view = new PageView();
114 view.show();
115 scope.viewport.append(curView.$el);
116 var s = '';
117 });
118 //!!!暂时不使用requireJS
119 // var self = this;
120 // requirejs([this.buildUrl(path)], function (View) {
121 // callback && callback.call(self, View);
122 // });
123 },
124 buildUrl: function (path) {
125 return this.viewRoot = path;
126 }
127 });
复制代码
好了,至此,我们粗制滥造版app结束,我们来试试先,再一并讲解其主要流程。
简单测试
html代码:
复制代码
1 <!DOCTYPE html>
2 <html xmlns="http://www.w3.org/1999/xhtml">
3 <head>
4 <meta charset="utf-8" />
5 <title></title>
6 <script src="res/libs/jquery.js" type="text/javascript"></script>
7 <script src="res/test/c.base.js" type="text/javascript"></script>
8 </head>
9 <body>
10 </body>
11 <script src="res/test/app.js" type="text/javascript"></script>
12 <script type="text/javascript">
13 var app = new Application();
14
15 </script>
16 </html>
复制代码
base代码:
base核心
app代码:
APP
文件结构:
测试结果
我可耻的觉得自己成功了一半了。。。
基本流程讲解
app是我们整个框架的核心,我们来简单讲解一下:
① 在整个_propertys_函数中,定义了我们app会用到的一些实例属性、方法
② init方法(一定会执行,因为我们使用了c.base的方法创建类),他主要干了两件事:
创建基本dom结构;
绑定事件,这个绑定事件就非常重要了
③ 59行开始,便是该文件的核心之一,这里为window绑定了hashchange事件,于是hash一旦改变(以#号方式),那么就会触发onhashchange事件
④ 触发hashchange事件后,会获得请求url#后面的参数,根据约定,他就是我们请求的view的路径,所以开始执行loadView方法,开始加载视图
⑤ 102行,开始加载视图,这里本应该使用requireJS,但是这里便于讲解,便于各位理解,我们暂时没有使用,于是动态加载我们的index文件,在成功后实例化view并且将view装入我们的视口中。
⑥ 整体流程结束
于是我们的粗制滥造版本也结束了。
阶段总结
好了,我们现在回过头来看看我们整个框架现在变成什么样了。
① 我们拥有实现类的通用b.class
② 我们有了我们的抽象视图类
③ 我们有了我们的control application
假使以上流程都流程问题不大,那么我们整个功能其实就七七八八了,因为还差的model可以轻松补上。
但是明显我们现在的APP是有缺陷的,而且缺陷比较大,比如我们的hash相关其实根本没有用上,所以现在我们来完善他们吧!
RequireJS组织代码
在这里,我们便开始使用我们的RequireJS了,然后将我们的整个逻辑慢慢铺开,首先我将我们的文件目录分开。
html页
main
app
c
c.base
c.view
index
至此我们的代码便完全分离开了,接下来我们来细化我们的app文件。
细化/清晰结构
现在来看看我们最后形成的结构:
我们现在来一层层剥离他。
唯一的一个页面demo
复制代码
1 <!DOCTYPE html>
2 <html xmlns="http://www.w3.org/1999/xhtml">
3 <head>
4 <meta charset="utf-8" />
5 <title></title>
6 <link rel="Stylesheet" type="text/css" href="res/style/main2.css" />
7 <link rel="Stylesheet" type="text/css" href="res/style/tuan.css" />
8 </head>
9 <body>
10 </body>
11 <script src="app/libs/require.js" data-main="main" type="text/javascript"></script>
12 </html>
复制代码
入口函数main
复制代码
1 window.BASEURL = '';
2 window.VIEWS_PATH = 'views/';
3
4 function getViewPath(path) {
5 return 'text!' + VIEWS_PATH + path + '.html';
6 }
7
8 require.config({
9 baseUrl: BASEURL,
10 shim: {
11 $: {
12 exports: 'jQuery'
13 },
14 _: {
15 exports: '_'
16 }
17 },
18 paths: {
19 '$': 'app/libs/jquery',
20 '_': 'app/libs/underscore',
21 'text': 'app/libs/require.text',
22
23 'c': 'app/common/c',
24 'cBase': 'app/common/c.base',
25 'cStorage': 'app/common/c.storage',
26 'cStore': 'app/common/c.store',
27
28 'cView': 'app/common/c.view',
29 'app': 'app/app',
30
31
32 's': 's'
33 }
34 });
35
36 require(['app'], function (APP) {
37 new APP();
38 });
复制代码
核心base/view
View Code
View Code
路由/Control APP
View Code
基本应用,视图与视图模板
复制代码
1 define(['$', '_', 'cBase', 'cView', getViewPath('index')], function ($, _, b, v, html) {
2 var View = b.Class(v.PageView, {
3 _propertys_: function () {
4 this.template = html;
5 this.url = 'http://wcf.open.cnblogs.com/blog/sitehome/recent/10'; //获取首页文章
6 },
7 init: function (superInit, request, interface) {
8 superInit(request, interface);
9 console.log('init');
10 },
11 createHtml: function () {
12 return this.template;
13 },
14 attrs: {
15 'data-id': 'test',
16 className: 'yexiaoc'
17 },
18 events: {
19 },
20 onCreate: function () {
21 console.log('onCreate');
22 },
23 //dom创建后数据加载时执行,用于加载后执行我们的逻辑
24 onLoad: function () {
25 console.log('onLoad');
26 $.get(this.url, function (data) {
27
28 var s = '';
29 });
30 },
31 //dom创建后,未显示
32 onShow: function () {
33 console.log('onShow');
34 },
35 //dom隐藏前
36 onHide: function () {
37 console.log('onHide');
38 }
39 });
40
41 return View;
42 });
复制代码
View Code
整体代码如上,现在我们来利用他做一个简单的应用
小试牛刀
我们来重新定义下我们的index,用它看看能不能实现微博功能。
我们知道我们该操作inde.js的onload事件,以加载微博数据:
PS:微博接口好像有所变化,我原来的方法不能用啦。。。
View Code
复制代码
1 onLoad: function () {
2 console.log('onLoad');
3 $.getScript(this.url, function (data) {
4 T.api("/statuses/home_timeline", null, "json", "GET")
5 .success(function (addResponse, hometimelineResponse) {
6 // 获取主页时间线数据
7 var data = addResponse.data.info;
8 var $timeline = $("#timeline");
9 $.each(data, function (i, item) {
10 $timeline.append("<li>" + item.origtext + "</li>");
11 });
12 }).error(function (code, message) {
13 alert("操作失败," + message);
14 });
15 });
16 },
复制代码
先不管其他的,我们来看看我们获得了什么:
PS:我这里直接用死数据,懒得去研究了。。。。。。确实熬不住了
最后的实例view模板代码:(相信我,你不会想点开的!!!)
View Code
结语
刚开始写感觉还不错,几个小时过去了,我感觉有点来不起了,暂时到这里吧,换个时间我们搞个更好的例子
本文转自叶小钗博客园博客,原文链接http://www.cnblogs.com/yexiaochai/p/3254111.html,如需转载请自行联系原作者