React Native
解决了H5
的性能问题,Weex
本质上也是React Native
,发展非常迅速,目前有替代原生开发的趋势。本人原本是iOS Native
开发的坚定支持者,原本打算从Objective-C
过渡到Swift
,就像在Windows
平台跟着微软走一样省心省力。无奈形式比人强,省钱省人工对企业由足够的吸引力,养家糊口是现实需求,情怀不能当饭吃,所以作为前端,还是要跟上时代步伐,多学一门技术。
在iOS Native
开发中,View Controller
不容易复用,代码又集中,所以很多聪明人想出了MVVM
等架构模型来给View Controller
减负。在React Native
中,发现这种优势天然存在,比如有一个this.state
,天然有界面观察者的作用,只要调用this.setState
,就能更新界面,这个相当于View Model
的作用了。在iOS Native
开发中,需要自定义一个View Model
结构体,并用上属性观察者这种特性,Swift
才有,才能达到类似效果。
ES6
之后,JavaScript
引入了class
关键字,面向对象的编程方法用起来就方便多了。同时,还有Promise
和async/await
,函数式编程的想法也很流行。由于本人iOS Native的编程时间更长,所以很自然地想把MVVM
这种想法带过来,形成一个三层架构模型。
简介
简单讲,就是将原来React Native
中一个registerComponent
,相当于View Controller
,能做完的事情,分为功能,逻辑,页面三层。将原来一个js
文件能搞定的事情分散到3~4
个不同的js
文件中。
userInterface
用户界面层,这部分按照React Native
来划分子模块。这里模块划分的标准是一张的的页面,复用的思路是组件。businessObject
业务对象层。这是业务逻辑层,按照面向对象的方法划分子模块,是一个个具体的业务概念,比如信息采集,贷款申请,个人信息管理等。functionModule
函数模块层。这是基础函数功能模块,按照函数式编程的思想划分子模块,是一个个具体的功能函数,比如网络取数据,缓存操作等等。
用户界面层
page:
这个代表一个个的页面,一般都是一个registerComponent
处理过的,是最顶层的发起者。component:
这是可复用的组件。这是React Native
的核心思想,框架本身也已经提供了足够丰富的组件供使用。当然这里主要的是对基础组件进行自定义组合,方便page:
中的页面调用。image:
这是静态资源,比如图片等constant:
这是常数集中定义的地方,比如界面共用的颜色,字体,尺寸,文字等等
这一层的主要工作就是集中精力把界面渲染出来,具体的功能和业务尽量都分出去。比如,设置页面标题,虽然很简单,也通过调用下面的逻辑层来实现,不需要自己做。
业务对象层
service:
这是公共服务对象,一般以单例的方式提供。比如页面跳转,主要是url的定义,可以集中写在这里。比如本地缓存,最主要的是key值的定义,可以集中写在一个文件中。比如远程网络访问,主要是一些url和参数的定义,可以集中写在一起。personal, enterprise:
这个按照具体的业务划分。比如,这里是企业业务和个人业务来划分文件夹的。Business:
这个名字可以固定,当然也可以用其他名字。他的作用是承接页面分出来的工作。打个比方,页面page
就像总裁,只要发号施令就可以了,比如响应保存按钮,处理文字录入等等;Business:
就像是页面这个总裁的助理,将所有业务都接过来,找人完成。ViewModel:
这个是用来替代this.state
的,主要保存页面需要展示的信息。需要更新的话,页面调用一下this.setState({});
就可以了。相对于this.state
,这个已经够好了,他的好处是可以把字段定义从页面中分离出来,并且可以用类的方式,将字段定义的更清晰,还可以提供处理函数,做一些页面逻辑工作。比如,把姓和名拼接成一个字段等。接上面的比方,ViewModel:
就相当于Business:
这个助理,根据page
总裁的指令,给出的具体工作成果。Model:
这个一般对应于网络返回数据。JavaScript
的网络传输返回的就是对象,字段还可以随时添加,非常灵活。不过没有名字,用起来跟dictionary
也差不多,key
基本靠猜。Model:
可以用类来定义,让大家有一个共同的地方来看字段定义。当然,类可以有成员函数,提供一定的数据处理能力。Business:
是按照业务逻辑来分的,跟页面的划分标准都不一样,所以Business
和page
之间并没有一一对应的要求。比如,这里的Business:
就为三个页面服务,搜索、信息输入、地址选择三个page
共用。如果做成单例的话,还可以用成员变量保存状态,省去了页面之间传递数据的麻烦。ViewModel:
一般是跟具体的page
一一对应的,因为这个本身定位就是相关page
显示需求。当然,对于一些比较复杂的page
,可能需要多个ViewModel:
来共同服务。Model:
一般跟具体的网络请求或者缓存对象对应,由Business:
来复杂持有和管理。对于page
来说是不可见的。page
这个总裁只关心需要显示的ViewModel
这种看得见的工作成果,至于实际上到底是谁做的,具体怎么做的,只要助理Business
清楚就可以了,他作为老总,没有必要知道。
函数模块层
- 这一层是按照函数式的编程思想来做的。对外提供的是一个个能够工作的函数。比如对话框,照相,网络访问,事件,路由等等。
async function actionSheet(title = '标题',
buttons = ['第一个按钮', '第二个按钮', '第三个按钮'],
cancelButtonText = '取消',
destructiveBtnIndex = -1) {
return new Promise((resolve, reject) => {
AlipayJSBridge.call('actionSheet',{
'title': title,
'btns': buttons,
'cancelBtn': cancelButtonText,
'destructiveBtnIndex': destructiveBtnIndex, // 变红按钮的index
}, data => {
const index = data.index;
const cancelIndex = buttons.length;
if (index < cancelIndex) {
return resolve(index);
} else {
return reject('选择了取消按钮');
}
});
});
}
export {
actionSheet,
};
比如这个是iOS开发中常见的action sheet,一般是Native实现,然后提供调用接口。这个是等待用户选择,然后根据选择结果进行相应处理。Native是以回调函数callback来实现异步过程的,在这里用了JavaScript的Promise包装,就可以在后续调用中使用async/await这种最新科技了。
- 为了方便使用,将输出接口在一个汇总文件中集中一下是个值得推荐的做法。比如:
export {
showLoading,
hideLoading,
} from './Loading';
export {
toast,
} from './Toast';
export {
alertNative,
confirm,
} from './Modal';
export {
actionSheet,
} from './Select';
- 这一层是具体功能提供者,不涉及具体业务,完成功能后的中间产物怎么组合,那是上面业务层的事,这里只要做好自己的本质工作就好了。接上面的比方,这里就相当开发、测试、运维、平面... ...等等具体干活的。
不足之处
这套架构模型的优点是分工明确,将界面、业务、功能分开来,对于比较成熟的产品是比较好的。并且把现在流行的面向对象编程和面向函数编程都包括进去了。
不过对于初创产品,或者比较简单的产品来说,体现不出优势,反而带来负担。最直白的来说,就是太烦了。
本来要改一点东西,只要找一个js文件,就是那个page
总裁页面,就可以了。现在弄得又要找business
助理,还要修改function
具体干活的,做完了还要转成View Model
这种指定的格式... ....
链路这么长,想想都头大,可能我只是修改一个后台返回字段而已啊,要改这么多地方... ...