本篇文章基于实战下的线上项目,给出基于vue技术栈实现方案。
一、所需工具
npm:包管理工具,前端开发基本都会用到
webpack: 模块打包工具,作用是将js模块或者一些不能被浏览器直接识别的第三方扩展语法(比如less、jsx语法等)进行打包编译,以便浏览器运行。
babel:可以让你用最新的js语法来写代码,如es6
二、框架体系
vue + vue-router + vuex
vue: 主流框架之一,以其数据驱动视图闻名于世,写代码简洁明了。组件化便利。
vue-router: vue路由套件,方便前端各种路由定义及跳转
vuex: 数据状态管理。vue多是组件化开发,但是各个组件如果需要共享同一个数据状态的时候,层层的数据传递显然不够优雅,而且容易出错,vuex可有效解决这样的问题。
三、架构设计
1、页面设计
组件化。每个功能模块都以组件化的方式存在,在页面中根据需要组装不同组件。组件共用的数据通过vuex共享数据状态。
组件化含义划分。组件化可包括以下几类:
(1)没有任何业务含义的组件。这类组件没有任何业务含义,可以在任何需要的地方是使用。比如公共标题栏、底部信息栏、通知等等。此时需要将这些组件单独放到一个模块(包)下。
(2)有共用业务基础的组件。如:短信验证组件、手机号码检测组件等等。这类组件多依赖于业务,但是又是各个业务公共的需要,因此可以单独放到一个公共业务模块(包)下。
(3)各个业务组件。这些组件有自己的业务逻辑,每个业务模块都应单独放到一起,简单清晰。
整体结构。这里的整体结构是考虑页面级别的,比如讲公共的区域放到同一个vue文件中,作为首先加载的页面,这样每个页面都可以共享该区域。典型结构如下
<nav></nav>
<body></body>
<bottom></bottom>
其中nav和bottom就是公共的区域。而body是具体的页面区域,所有的页面渲染、变更都在此区域。如果基于vue-router来讲,body即可替换为
<router-view></router-view>
2、路由设计
上文说过,本技术栈是基于vue-router来进行页面路由的,为什么还需要路由设计?其实这里并不是设计路由,而是基于vue-router来更好的做路由管控。
(1)路由控制
这里所说的路由控制是指,所有的路由都必须经过一层管控,这层管控可以做很多东西,诸如打点、白名单控制等等。基于vue-router的路由控制代码如下:
router.beforeEach((to, from, next) => {next()});
这样,我们就可以在这个方法中做一些公共的处理或者拦截等。
(2)router配置
这里的router配置更多的是指router路径的定义和存放位置。router路径的定义首先要有一定的命名意义,其次应将他们统一写到一个类似于router.js中。
3、网络访问模块
这个网络访问是指整个系统的api访问入口。因为每个网络请求后端都会返回统一的处理结果的状态值。比如该接口处理失败、处理超时、处理成功等都会有统一的状态响应code,如果放到单个的网络请求中进行处理,显然相当麻烦,因此需要抽象出一个公共的网络访问模块进行统一处理。接口只需要拿到自己需要的数据区域的值即可。
此外,为了便于管理各个网络请求api接口,我们将这些网络接口api统一到一个文件中,做成可配置的。这个文件允许我们定义api接口及其需要的参数。如下所示
const config = {
//获取通知api
getNotice: {
api: 'getNotice'//api 名称
},
//获取首页数据api
getHomeData: {
api: "homeData",
params: {//api需要传入的参数
productId: {
type: [String, Number],//参数类型
required: true//是否必须
}
},
}
最后增加一个api校验模块,用于在api网络请求调用的时候校验参数的合法性。最终请求网络封装接口如下所示(注意是伪代码示例):
const isRequesting = {};//防重复请求
const invalidRequest = new Promise((resolve, reject) => {
});
for (let item in AllAPI) {
if (AllAPI.hasOwnProperty(item)) {
if (isRequesting[apiId]) {
Vue.prototype.$message(Constant.MSG_NETWORK_REQUESTING);
return invalidRequest;
}
return AllAPI[item](params).then(res => {
loading && loading.close();
isRequesting[apiId] = false;
if (res.success ) {//业务逻辑执行成功,返回data域,不附带code
return res.result
}
if (res.code === Code.ERROR) {
Vue.prototype.$message(res.message || Constant.MSG_NETWORK_ERROR);
return false
}
}, (error) => {
loading && loading.close();
isRequesting[apiId] = false;
Vue.prototype.$message(Constant.MSG_NETWORK_ERROR)
})
}
}
}
网友评论