Vue Mage — «Классификация» API

Vue.js
Vue Mage — «Классификация» API

предисловие

Все модули, все вещи можно классифицировать. Без лишних слов, Сирия, прямо в тему.

API классификации

  • Среда: Vue2+ или Vue3+

Давайте строить быстро и быстро с VueCLI здесь

vue create vue-api-module

Получите следующий каталог

--src
----store
------index.js
----App.vue
----main.js

Затем создайте новый файл api.js следующим образом:

--src
----services
------api.js
----store
------index.js
----App.vue
----main.js

API базового класса

Сначала мы создаем базовый класс следующим образом:

class BaseApiService {
  baseUrl = "https://jsonplaceholder.typicode.com";
  resource;

  constructor(resource) {
    if (!resource) throw new Error("Resource is not provided");
    this.resource = resource;
  }

  getUrl(id = "") {
    return `${this.baseUrl}/${this.resource}/${id}`;
  }

  handleErrors(err) {
    // 处理错误:
    console.log({ message: "Errors is handled here", err });
  }
}
  • baseUrl: установить корневой путь запроса;
  • ресурс: источник;
  • getUrl: получить функцию ссылки, включая baseUrl, ресурс, идентификатор;
  • CanderRors: обрабатывать функцию ошибки;

API класса только для чтения

Затем мы создаем подкласс, который содержит методы fetch, get только для чтения.

class ReadOnlyApiService extends BaseApiService {
  constructor(resource) {
    super(resource);
  }
  async fetch(config = {}) {
    try {
      const response = await fetch(this.getUrl(), config);
      return await response.json();
    } catch (err) {
      this.handleErrors(err);
    }
  }
  async get(id) {
    try {
      if (!id) throw Error("Id 不合法");
      const response = await fetch(this.getUrl(id));
      return await response.json();
    } catch (err) {
      this.handleErrors(err);
    }
  }
}
  • выборка: получить данные;
  • получить: получить данные по идентификатору;

Написать API класса

Далее создаем подкласс с доступными для чтения и записи методами: post, put, delete

class ModelApiService extends ReadOnlyApiService {
  constructor(resource) {
    super(resource);
  }
  async post(data = {}) {
    try {
      const response = await fetch(this.getUrl(), {
        method: "POST",
        body: JSON.stringify(data)
      });
      const { id } = response.json();
      return id;
    } catch (err) {
      this.handleErrors(err);
    }
  }
  async put(id, data = {}) {
    if (!id) throw Error("Id 不合法");
    try {
      const response = await fetch(this.getUrl(id), {
        method: "PUT",
        body: JSON.stringify(data)
      });
      const { id: responseId } = response.json();
      return responseId;
    } catch (err) {
      this.handleErrors(err);
    }
  }
  async delete(id) {
    if (!id) throw Error("Id 不合法");
    try {
      await fetch(this.getUrl(id), {
        method: "DELETE"
      });
      return true;
    } catch (err) {
      this.handleErrors(err);
    }
  }
}
  • пост: создать данные;
  • Поместите: обновлять данные;
  • Удалить: Удалить данные;

наследовать

Давайте рассмотрим два простых примера наследования:

class UsersApiService extends ReadOnlyApiService {
  constructor() {
    super("users");
  }
}
class PostsApiService extends ModelApiService {
  constructor() {
    super("posts");
  }
}

[Класс UsersApiService] наследует API класса только для чтения — ReadOnlyApiService, который может использовать методы выборки и получения. [Класс PostsApiService] наследует API класса чтения-записи — ModelApiService, который может использовать пять методов: fetch, get, post, put, delete.

Мы также можем написать унаследованные классы API в соответствии с бизнесом:

class AlbumsApiService extends ModelApiService {
  constructor() {
    super("albums");
  }
  async uploadImage() {
    /*
    这里可以写你的上传图片逻辑
     */
    console.log({ message: "图片上传成功!" });
    return true;
  }

  async triggerError() {
    try {
      throw Error(" API 模块调用错误!");
    } catch (err) {
      this.handleErrors(err);
    }
  }
}

экспорт

Мы экспортируем эти API в api.js:

export const $api = {
  users: new UsersApiService(),
  posts: new PostsApiService(),
  albums: new AlbumsApiService()
};

Практика API классификации

Как вызвать вышеуказанные классы API в проекте Vue? В основном мы называем это в Vuex и компонентах:

storePlugins

  1. Сначала создайте storePlugins.js:
--src
----plugins
------storePlugins.js
----services
------api.js
----store
------index.js
----App.vue
----main.js
  1. Добавьте api.js в storePlugins.js:
import { $api } from "@/services/api";

export default function(store) {
  try {
    store.$api = $api;
  } catch (e) {
    console.error(e);
  }
}
  1. Добавьте плагин в src/store/index.js:
...
import storePlugins from "@/plugins/storePlugins";
...
export default new Vuex.Store({
  plugins: [storePlugins],
  state: {
  ...
});

mixins

  1. Создайте mixins.js в следующем месте:
--src
----plugins
------mixins.js
------storePlugins.js
----services
------api.js
----store
------index.js
----App.vue
----main.js
  1. Суеверие.
import Vue from "vue";
import { $api } from "@/services/api";

Vue.mixin({
  computed: {
    $api: () => $api
  }
});
  1. main.js представляет миксины по всему миру:
...
import "@/plugins/mixins";
...

передача

OK! Теперь вы можете вызвать его в магазине и компонентах, например:

this.$api.{resource}.{method}
------
this.$api.users.fetch({})
this.$api.users.get(1)
this.$api.posts.post(post)
this.$api.posts.put(post)
this.$api.posts.delete(1)
this.$api.albums.uploadImage()
this.$api.albums.triggerError()

Пример

Можно отлаживать локально~

  • Компоненты
<template>
  <div id="app">
    <h1>Vue API “类化” 示例</h1>
    <p>请打开控制台</p>
    <p>检查 Vuex store</p>
  </div>
</template>

<script>
export default {
  name: "App",
  async created() {
    // 获取用户资料
    await this.$store.dispatch("fetchUsers");
    const users = await this.$api.users.fetch({});
    console.log({ message: "Users from the component", users });
    // 根据 id 获取用户资料
    const user = await this.$api.users.get(1);
    console.log({ message: "User with id: 1", user });
    // 创建新文章
    let post = {
      userId: 1,
      title: "测试文章",
      body:
        "这是一篇测试文章"
    };
    await this.$store.dispatch("createPost", post);
    // 更新文章
    post = { ...post, id: 1 };
    await this.$store.dispatch("updatePost", post);
    // 删除文章
    await this.$api.posts.delete(post.id);
    console.log({ message: "成功删除文章!" });
    // 执行自定义方法
    await this.$api.albums.uploadImage();
    // 执行自定义方法
    await this.$api.albums.triggerError();
  }
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
  • Магазин
import Vue from "vue";
import Vuex from "vuex";
import storePlugins from "@/plugins/storePlugins";

Vue.use(Vuex);

const ADD_USERS = "ADD_USERS";
const ADD_POST = "ADD_POST";
const UPDATE_POST = "UPDATE_POST";

export default new Vuex.Store({
  plugins: [storePlugins],
  state: {
    users: [],
    posts: []
  },
  mutations: {
    [ADD_USERS](state, users) {
      state.users = users;
    },
    [ADD_POST](state, post) {
      state.posts = [...state.posts, post];
    },
    [UPDATE_POST](state, post) {
      const index = state.posts.findIndex(({ id }) => id === post.id);
      if (!~index) state.posts.splice(index, 1, post);
    }
  },
  actions: {
    async fetchUsers({ commit }, config) {
      const users = await this.$api.users.fetch(config);
      commit(ADD_USERS, users);
      console.log({ message: "Vuex 中的用户数据", users });
    },

    async createPost({ commit }, post) {
      const id = await this.$api.posts.post(post);
      commit(ADD_POST, { ...post, id });
      console.log({ message: "创建文章", post: { ...post, id } });
    },

    async updatePost({ commit }, post) {
      const id = await this.$api.posts.put(post.id, post);
      commit(UPDATE_POST, post);
      console.log({ message: "更新文章", post: { post, id } });
    }
  }
});

Эпилог

Зачем так писать?

Бен Гуа считает: если ваш бизнес отличается таким образом, то и API нужно синхронизировать. Во-первых, мысль ясна, следи за делом, во-вторых, лучше масштабируемость и переиспользуемость, в-третьих, выглядит очень продвинуто... 😀😀😀

  • обычный
// 获取文章
export const getPost = params => {
  return axios.get(`/interface/getPost/`)
}

// 新增文章
export const addPost = params => {
  return axios.post(`/interface/addPost`, params)
}

// 修改文章
export const updatePost = params => {
  return axios.post(`/interface/updatePost/`, params)
}

......
import {getPost,addPost,updatePost} from '@/services/api'
  • передовой
class PostsApiService extends ModelApiService {
  constructor() {
    super("posts");
  }
}
this.$api.posts.post(param)

На этот раз я здесь, я Энтони из Наггетс, я не безжалостен и много болтаю! Публичный номер [Наггетс Энтони].

Ставь лайк и двигай ручонкой, мы с тобой вместе устремимся вперёд~ До свидания~