1. Model 编程
1.1 介绍
Model 编程, 即模块化编程; 是指将业务分割成为一个个模块, 每个模块拥有特定的功能, 通过继承和组合完成功能的组合; 它其实就是面向对象编程的拓展.
Model 编程最适合的内容为定义前端API 内容, 将API 实现封装, 在封装层实现数据的处理和转发; UI 界面只需要调用数据即可, 不需要处理数据的目的; 达到在各个分层中, 只需要集中处理本层的核心内容, 其他内容直接通过调用获取.
1.2 为什么要使用Model 编程
在前端界面中, 请求数据的方法有: AJAX, Axios, Fetch, 在这里我们约定一下: 我们将数据请求的方法称为API
API 可分为如下几个组成部分:
- API的方法
- 数据请求的接口
- 数据的处理
按照一般思维, 我们会将这些内容合并处理, 即在一个界面中先拿到数据, 处理数据之后然后渲染到界面中.
这种方式确实写起来很方便, 因为我们只需要关注业务逻辑即可
但是, 如果此时业务场景变更了:
如果API 方法变了, 那么是不是我们必须修改所有界面的请求?
如果请求的接口变了, 那么我们是不是需要修改所有页面的URL?
如果后端擅自把数据格式变了, 那么我们是不是需要整理寻找业务处理逻辑, 然后去修改?
如果项目小, 可能上面的问题不会是问题, 但是如果一个项目可能有大量迭代维护的需求, 我们就需要考虑抽象的合理性和迭代的成本, 因为数据请求涉及的层次往往会非常多, 如果不进行合理地封装, 那么会导致迭代成本非常高(修改内容过多)
而Model 编程就可以解决上述问题, 下面我们来介绍一下Model 对于API 的处理思路
1.3 Model API 处理思路
各个界面对应的功能:
- 后端Server: 后端服务器, 用于提供请求的数据信息
- API: 实现请求方式(AJAX, Axios, Fetch)的封装
- Professinal API: 整合请求, 将请求模块化; 例如, 一个项目可以分为如下模块: 用户信息模块, 权限模块, 具体业务模块, 数据可视化模块
- Model 抽象层: 定义Model 通用的方法
- Model: 先通过调用Professinal API 拿到后端传递过来的原始数据, 然后处理数据
- UI 界面: 想Model 层调用处理之后的数据, 然后进行页面渲染
2. Model 的分层
3.1 服务器
对于前端来说, 服务器是指后端提供的接口内容;
3.2 API 基类
一个项目用来请求数据的方式, 一般项目leader 会对请求方式进行基本封装, 最常见的数据请求方式是ajax
实例代码:
const _ajax = (method, url, data) => {
let p = new Promise((resolve, reject) => {
// Fetch API
// axios
let r = new XMLHttpRequest()
r.open(method, url, true)
r.setRequestHeader('Content-Type', 'application/json')
r.onreadystatechange = () => {
if (r.readyState === 4) {
if (r.status === 200) {
let response = JSON.parse(r.response)
resolve(response)
} else {
reject({
success: false,
})
}
}
}
r.send(data)
})
return p
}
class Ajax {
constructor(baseUrl) {
// 定义统一的接口,这样后面就可以直接引用了;后期如果需要更改这样也容易改
this.baseUrl = baseUrl || 'http://localhost:8000/'
// console.log(this.baseUrl)
}
get(path) {
let url = this.baseUrl + path
console.log(url)
return _ajax('GET', url, '')
}
post(path, data) {
let url = this.baseUrl + path
data = JSON.stringify(data)
return _ajax('POST', url, data)
}
}
export default Ajax
3.3 业务API
在一个项目中, 业务可以分为很多个模块;
比如在之前公司上班的时候, 自己负责的就是图表模块, 表格显示模块, 首页的显示模块
这些模块如果是自己负责, 其他开发人员不参与其中的话, 我们可以将这些模块按照model 编程处理, 这样虽然最开始加大了一点工作量, 但是到后期很容易维护!
如果是多个人一同负责一个模块, 那么使用model 处理就需要和其他人商量着来.
在业务API 这一层, 我们将一个模块的请求汇总在一起集中处理
实现代码
import Api from './api'
class IpApi extends Api {
constructor(props) {
super('https://httpbin.org/ip');
}
getIp() {
return this.get('')
}
}
export default IpApi
3.4 model模块API
这一层主要是做数据处理, 将后端传递过来的数据处理成我们想要的数据格式, 然后定义一个函数进行数据转发, 转发的地点是应用层
import IpApi from '../api/IpApi'
import Model from './Model'
class IpModel extends Model{
constructor() {
super()
this.api = new IpApi()
}
getIp() {
let p = this.api.getIp()
return p.then((ip) => {
return ip.origin
})
}
}
export default IpModel
3.5 业务层
在这一层, 我们直接拿到了我们需要的数据格式, 因此只用将重心集中在页面渲染即可. 我们只需要关系渲染的逻辑, 而不需要关系数据的获取以及处理过程.
3. demo
3.1 场景描述
现在需要渲染两个数据:
- 通过接口: https://httpbin.org/ip 接口获取IP地址
- 通过接口: https://free-api.heweather.net/s6/weather/now?location=${location}&key=cc8fb05bb74c41f3ad6121e9f2826eb7 获取城市的天气