1. Model 编程

1.1 介绍

Model 编程, 即模块化编程; 是指将业务分割成为一个个模块, 每个模块拥有特定的功能, 通过继承和组合完成功能的组合; 它其实就是面向对象编程的拓展.

Model 编程最适合的内容为定义前端API 内容, 将API 实现封装, 在封装层实现数据的处理和转发; UI 界面只需要调用数据即可, 不需要处理数据的目的; 达到在各个分层中, 只需要集中处理本层的核心内容, 其他内容直接通过调用获取.

1.2 为什么要使用Model 编程

在前端界面中, 请求数据的方法有: AJAX, Axios, Fetch, 在这里我们约定一下: 我们将数据请求的方法称为API

API 可分为如下几个组成部分:

  1. API的方法
  2. 数据请求的接口
  3. 数据的处理

按照一般思维, 我们会将这些内容合并处理, 即在一个界面中先拿到数据, 处理数据之后然后渲染到界面中.

这种方式确实写起来很方便, 因为我们只需要关注业务逻辑即可

但是, 如果此时业务场景变更了:

如果API 方法变了, 那么是不是我们必须修改所有界面的请求?

如果请求的接口变了, 那么我们是不是需要修改所有页面的URL?

如果后端擅自把数据格式变了, 那么我们是不是需要整理寻找业务处理逻辑, 然后去修改?

如果项目小, 可能上面的问题不会是问题, 但是如果一个项目可能有大量迭代维护的需求, 我们就需要考虑抽象的合理性和迭代的成本, 因为数据请求涉及的层次往往会非常多, 如果不进行合理地封装, 那么会导致迭代成本非常高(修改内容过多)

而Model 编程就可以解决上述问题, 下面我们来介绍一下Model 对于API 的处理思路

1.3 Model API 处理思路

各个界面对应的功能:

  1. 后端Server: 后端服务器, 用于提供请求的数据信息
  2. API: 实现请求方式(AJAX, Axios, Fetch)的封装
  3. Professinal API: 整合请求, 将请求模块化; 例如, 一个项目可以分为如下模块: 用户信息模块, 权限模块, 具体业务模块, 数据可视化模块
  4. Model 抽象层: 定义Model 通用的方法
  5. Model: 先通过调用Professinal API 拿到后端传递过来的原始数据, 然后处理数据
  6. 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 场景描述

现在需要渲染两个数据:

  1. 通过接口: https://httpbin.org/ip 接口获取IP地址
  2. 通过接口: https://free-api.heweather.net/s6/weather/now?location=${location}&key=cc8fb05bb74c41f3ad6121e9f2826eb7 获取城市的天气

3.2 链接

Model Demo