# 为什么需要模型层(数据处理)

在 vue 的组件中,我们一般需要在 created 或者 mounted 中通过 api 来获取需要渲染到视图上的数据,或者在 methods 中获取数据,如果把这些逻辑都写在这里,会显得非常冗杂,如果把这部分 api 相关的抽离出来,单独封装,这样可以大大提升代码的可读性与可维护性。下面以 日志 这个业务逻辑来说明:

<script>
import log from 'lin/models/log' // 日志类的实例

export default {
  async created() { // created钩子
      await this.initPage()
  },

  methods: {
      // 页面初始化
      async initPage() {
        try {
          this.users = await log.getLoggedUsers({}) // api请求
          const res = await log.getLogs({ page: 0 }) // api请求
          this.logs = res.collection
        } catch (err) {
          console.error(err)
        }
      },
  }
}
</script>

这里的 log 是日志类的实例,把所有跟日志相关的 api 封装在 Log 这个类中,这里就叫日志模型。在这个 Log 类中有很多相关日志获取的方法,如果有业务逻辑变动,只需要修改相关方法即可。我们把每个业务模型独立成一个 js 文件,声明一个类通过其属性和方法来实现这个模型相关的数据获取。

# 怎么来封装一个模型

我们来假设这样一个场景:有一个图书的后台管理系统,在图书管理这个模块,初始化的时候要看到已经上架的图书,点击图书可以看到详情,可以更改图书的上下架状态,可以删除图书。这其实是服务端典型的增删改查,我们既然采用前后端分离模式,这部分的处理就自然就是前端的职责了。

首先,当前这个业务模型是图书,那就可以创建一个 Book 类,管理员对图书的增加、删除、修改、查看这些行为分别对应类中的方法,这里已经有四个方法了。

import { get, post, put, _delete } from '../utils/http'

// 我们通过 class 这样的语法糖使模型这个概念更加具象化,其优点:耦合性低、可维护性。
export default class Book {
  constructor() {}

  // 类中的方法可以代表一个用户行为
  async addBook(info) {
    const res = await post('v1/book', { info })
    return res
  }

  // 在这里通过 async await 语法糖让代码同步执行
  // 1. await 一定要搭配 async 来使用
  // 2. await 后面跟的是一个 Promise 对象
  async editBook(id) {
    const res = await put('v1/book', { id })
    return res
  }

  // static 方法修饰的成员不再属于某个对象,而是属于它所在的类。
  // 只需要通过其类名就可以访问,不需要再消耗资源反复创建对象。
  static async delectBook(id) {
    const res = await _delete(`v1/book/${id}`)
    return res
  }

  async getBooks() {
    const res = await get('v1/book')
    return res
  }
}

# 小结

本小节主要还是介绍思想,将设计模式应用到前端代码中来,也是需要我们共同学习的,对于我们程序猿来说写代码是我们的工作,更是一种热爱,怎样让代码更加优雅更加有艺术感是一个长期话题,愿与君共勉。