[原创]分享我们⾃⼰搭建的⼩程序开发框架——wframe及设
计思想详解
wframe不是控件库,也不是UI库,她是⼀个⼩程序⾯向对象编程框架,代码只有⼏百⾏。她的主要功能是规范⼩程序项⽬的⽂件结构、规范应⽤程序初始化、规范页⾯加载及授权管理的框架,当然,wframe也提供了⼀些封装好了的函数库,⽅便开发者调⽤。
wframe⽬前已实现的核⼼功能:
1. 应⽤程序初始化⾃动从服务器获取配置,ajax成功后触发ready事件;
2. 每个页⾯对象可以配置是否requireLogin属性,如果需要登录,则每个页⾯在进⼊ready⽅法之前会⾃动完成授权、获取⽤户信息、服务器端登录;
3. 完成ajax全局封装:如果⽤户已经登录,则会⾃动在http-header添加token信息,如果session过期则会重新进⼊登录流程;
本⽂的阅读对象:想要⾃⼰搭建⼩程序框架的⼈,相信本⽂会给你提供⼀些思路。
我们为什么要开发wframe?
我们开发的⼩程序越来越多,⼩程序也越来越复杂,于是我们就想将每个⼩程序重复在写的那⼀部分代码提出来,变成⼀个公共的函数库,⼀个跟每个项⽬的业务逻辑完全不相关的函数库。除了在新项⽬中可以节省代码之外,有⼀些复杂的代码逻辑由于提到了公共的函数库,我们将其优化得更优雅、更健壮。
说wframe是⼀个函数库虽说也可以,但wframe更像⼀个框架。我们通常把⼀些静态⽅法、静态对象、仅处理页⾯内容的JS⽂件集称作函数库,⽐如jQuery;我们通常把处理了应⽤程序和页⾯⽣命周期,以及使⽤了⼤量的⾯向对象编程技术的JS⽂件集称作框架。因此,wframe 其实是⼀个框架。
重要说明:wframe框架⽤到了⼤量的⾯向对象编程知识,⽐如实例、继承、覆写、扩展、抽象⽅法等等,因此对开发⼈员,特别是项⽬中的架构师,的⾯向对象编程能⼒有较⾼要求。
项⽬源码已上传到GitHub并会持续更新:
⼀、wframe项⽬结构
wframe的最核⼼的职责就是规范项⽬⽂件结构。
为什么需要规范呢?因为我们⼩程序越来越多,如果每个⼩程序的⽂件结构都不⼀样的话,那定是⼀件很难受的事。另外,wframe由于其框架的⾝份,其本职⼯作就是定义⼀个最好的⽂件结构,这样基
于wframe创建的所有⼩程序都将⾃动继承wframe的优秀品质。
1. _core⽂件夹
wframe框架源码,与业务毫不相⼲,每个⼩程序都可以直接将_core⽂件夹复制到项⽬中,⽽当wframe更新版本时,所有⼩程序可以直接覆盖_core完成升级。⽤下划线“_”开头的⽬的有2个:
(a) 将此⽂件夹置顶;
(b) 标记此⽂件夹是⼀个特殊⽂件夹,本框架中还有其他地⽅也会⽤到下划线开头为⽂件夹/⽂件。
2. _demo⽂件夹
业务核⼼⽂件夹,⽐如定义⼀些扩展wframe框架的类,同时这些类⼜被具体的业务类继承使⽤,⽐如ViewModelBase等。
3. pages⽂件夹
与⼩程序官⽅⽂档定义⼀致:放置页⾯的地⽅。
4. app.js
程序主⼊⼝,只不过基于wframe的⼩程序的app.js跟官⽅的长得很不⼀样,我们定义了⼀个⾃⼰的Applicaiton类,然后再new的⼀个Application实例。稍后详解。
5. mvcApp.js
⼏乎每个js⽂件都会require引⼊的⼀个⽂件,因为这相当于是项⽬的静态⼊⼝,其包含了所有的静态函数库,⽐如对wx下⾯⽅法的封装、Array类扩展、Date类扩展、⽹络请求(ajax)封装等等。mvcApp.js⼏乎只定义了⼀个⼊⼝,其内部的很多对象、⽅法都是通过require其他JS引⼊的。因此,⼤多数情况下,我们只需要require引⼊mvcApp.js就够了。
写到这⾥,分享⼀个我们的编程思想:⼊⼝要少。⼩程序⾥有哪些⼊⼝:this、getApp()、wx、mvcApp。其实也就是每⼀⾏代码点号“.”前⾯的都叫代码⼊⼝。
我们还有另⼀个编程规范(强制):每个⽂件不能超过200⾏代码(最好不超100⾏)。这就是要求每个程序员必须学会拆分,拆分也是我们的另⼀个编程思想。通过拆分,每个JS⽂件职责清晰,极⼤的提⾼了代码阅读率。
⼆、详解
1. app.js和Application类详解
app.js定义了程序⼊⼝。
1var mvcApp = require('mvcApp.js');
2var Application = require('_core/Application.js');
3
4function MvcApplication() {
5 Application.call(this);
6this.initUrl = 'www.somdomain/api/client-config/get?key=wx_applet_wframe';
7this.host = 'localhost:18007';
9 host: 'localhost:18007',
10 cdn: 'images.local-dev.cdn.somedomain'
11 };
13this.accessToken = null;
14this.useDefaultConfigsOnInitFailed = false;
15 };
16
17 MvcApplication.prototype = new Application();
18
19 Initialized = function (configs) {
20if (configs != null && configs !== '') {
22this.host = figs.host;
23 }
24 };
jquery框架定义25
26 App(new MvcApplication());
可以看到app.js定义了⼀个MvcApplication类,继承⾃框架中的Application类,同时重写了⽗类的onInitialized⽅法。
下⾯是框架中的Application类:
1var WebClient = require('http/WebClient.js');
2var AuthorizeManager = require('weixin/AuthorizeManager.js');
3var weixin = require('weixin.js');
4
5
6function Application() {
7this.initUrl = '';
8this.host = '';
9this.session = null;
10this.initialized = false;
12this.useDefaultConfigsOnInitFailed = false;
13this.authorizeManager = new AuthorizeManager();
14this._userInfo = null;
15this._readyHandlers = [];
16 };
17
18 Application.prototype = {
19 onLaunch: function () {
20var me = this;
21if(this.initUrl === ''){
22throw 'please create YourOwnApplication class in app.js that inerits from Application class and provide initUrl in constructor';
23 }
24var client = new WebClient();
25 client.post(this.initUrl, null, function(result){
26if (result.success || me.useDefaultConfigsOnInitFailed){
27 me.initialized = true;
28 me.onInitialized(result.success ? result.value : null);
29 me.triggerReady();
30 }
31else{
32 weixin.alert('⼩程序初始化失败', ssage);
33 }
34 }, '初始化中...');
35 },
36 onShow: function () {
37
38 },
39 onHide: function () {
40
41 },
42 onError: function () {
43
44 },
45 onPageNotFound: function () {
46
47 },
48 ready: function (callback) {
49var me = this;
50if (this.initialized === true) {
51 callback && callback();
52return;
53 }
54this._readyHandlers.push(callback);
55 },
56 triggerReady: function () {
57for (var i = 0; i < this._readyHandlers.length; i++) {
58var callback = this._readyHandlers[i];
59 callback && callback();
60 }
61this._readyHandlers = [];
62 },
63 onInitialized: function(configs){
64
65 },
66 getUserInfo: function(callback){
67var me = this;
68if(this._userInfo != null){
69 callback && callback(this._userInfo.userInfo);
70return;
71 }
UserInfo(function(result){
73 me._userInfo = result;
74 callback && callback(me._userInfo.userInfo);
75 });
76 },
77 getCurrentPage: function(){
78var pages = getCurrentPages();
79return pages.length > 0 ? pages[0] : null;
80 }
81 };
82
ports = Application;
Applicaiton类(及其⼦类)在wframe框架中的主要⼯作:
1. 应⽤程序初始化的时候从服务器获取⼀个配置,⽐如服务器域名(实现域名实时切换)、CDN域名,以及其他程序配置信息;
2. 全局存储⽤户的授权信息和登陆之后的会话信息;
3. 全局mock开关;
4. 其他快捷⽅法,⽐如获取当前页⾯等。
Application类核⼼执⾏流程:
1. 应⽤程序初始化时⾸先从服务器获取客户端配置信息;
2. 获取完成之后会触发onInitialized⽅法(在⼦类中覆写)和ready⽅法。
2. PageBase类详解
PageBase类是所有页⾯都会继承的⼀个基类。先看代码:
1 console.log("PageBae.js entered");
2
3 const app = getApp();
4
5function PageBase(title) {
6this.vm = null;
7this.title = title;
9 };
10
11 PageBase.prototype = {
12 onLoad: function (options) {
13var me = this;
14if (this.title != null) {
15this.setTitle(this.title);
16 }
18 ady(function () {
19if (me.requireLogin && app.session == null) {
20 UserInfo(function (info) {
21 me.login(info, function (session) {
22 app.session = session;
23 me.ready(options);
24 });
25 });
26 }
27else {
28 me.ready(options);
29 }
30 });
31 },
32 ready: function (options) {
33
34 },
35 onPreload: function(options){
36
37 },
38 render: function () {
39var data = {};
40for (var p in this.vm) {
41var value = this.vm[p];
42if (!this.vm.hasOwnProperty(p)) {
43continue;
44 }
45if (value == null || typeof (value) === 'function') {
46continue;
47 }
48if (value.__route__ != null) {
49continue;
50 }
51 data[p] = this.vm[p];
52 }
53this.setData(data);
54 },
55 go: function (url, addToHistory) {
56if (addToHistory === false) {
57 wx.redirectTo({ url: url });
58 }
59else {
60 wx.navigateTo({ url: url });
61 }
62 },
63 goBack: function () {
64 wx.navigateBack({});
65 },
66 setTitle: function (title) {
67this.title = title;
68 wx.setNavigationBarTitle({ title: this.title });
69 },
70 login: function (userInfo, callback) {
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论