【類】和【接口】是 JavaScript 將來的方向,咱們的 API 調用也將如此,朝着這個方向和業務模塊同步分類、同步升級。本文講的正是 —— Vue 魔法師,如何將 API 「類化」?vue
萬物皆模塊,萬物可歸類。閒言少敘,直接正題。ios
咱這裏直接 VueCLI 迅速快捷構建web
vue create vue-api-module
複製代碼
獲得以下目錄vuex
--src
----store
------index.js
----App.vue
----main.js
複製代碼
而後新建文件 api.js 以下,json
--src
----services
------api.js
----store
------index.js
----App.vue
----main.js
複製代碼
咱們先建立一個基礎類以下:axios
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 });
}
}
複製代碼
而後,咱們再建立一個子類:包含 fetch、get 只讀方法。api
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);
}
}
}
複製代碼
接着,咱們再建立一個包含可讀寫方法的子類:post、put、deletemarkdown
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);
}
}
}
複製代碼
讓咱們看看兩個簡單的繼承示例:app
class UsersApiService extends ReadOnlyApiService {
constructor() {
super("users");
}
}
複製代碼
class PostsApiService extends ModelApiService {
constructor() {
super("posts");
}
}
複製代碼
【UsersApiService 類】繼承了只讀類 API —— ReadOnlyApiService,能夠使用 fetch、get 兩種方法。而 【PostsApiService 類】繼承了讀寫類 API —— ModelApiService,能夠使用 fetch、get、post、put、delete 五種方法。async
咱們也能夠根據業務來寫繼承 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.js 導出這些 API:
export const $api = {
users: new UsersApiService(),
posts: new PostsApiService(),
albums: new AlbumsApiService()
};
複製代碼
在 Vue 項目中如何調用以上的 API 類?咱們主要在 Vuex 和 components 中調用它:
--src
----plugins
------storePlugins.js
----services
------api.js
----store
------index.js
----App.vue
----main.js
複製代碼
import { $api } from "@/services/api";
export default function(store) {
try {
store.$api = $api;
} catch (e) {
console.error(e);
}
}
複製代碼
...
import storePlugins from "@/plugins/storePlugins";
...
export default new Vuex.Store({
plugins: [storePlugins],
state: {
...
});
複製代碼
--src
----plugins
------mixins.js
------storePlugins.js
----services
------api.js
----store
------index.js
----App.vue
----main.js
複製代碼
import Vue from "vue";
import { $api } from "@/services/api";
Vue.mixin({
computed: {
$api: () => $api
}
});
複製代碼
...
import "@/plugins/mixins";
...
複製代碼
OK!如今你就能夠在 store 和 components 中調用了,例如:
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)
複製代碼
本次就到這裏,我是掘金安東尼,人不狠,話也多!公衆號【掘金安東尼】。
點贊小手動一動,你我一塊兒向前衝~ 再會~