前言
前端系统开发中, 由于功能的复杂性后台的数据接口会很多, 如果每个请求都写在相应的页面中维护起来特别繁琐, 所以就需要一个统一管理 API 的地方, 已达到快速定位, 这时候就需要请求与 API 模块相关联, 以实现相应的操作.
对 axios 库进行基本封装
项目中使用的 Ajax 请求库是 axios, 关于 axios 配置及拦截就不在这复述, 网上例子很多, 直接上二次封装的代码
- import API from './api'; // 存放 API 的模块
- import axios from '@/config/axios'
- import {Message} from 'element-ui'
- import {merge,path,isArray} from '@/assets/js/tool' // 自定义封装的辅助函数工具
- const placeholder=/\{(\w+)\}?/gi; // 占位符
- export class Fetch {
- constructor(baseURL){
- this.baseURL=baseURL || '/api';
- this.headers=axios.defaults.headers;
- }
- // 这里是提交请求的入口, 返回一个 promiss
- commit(url,payload,showMes){
- const req= path(isArray(url)?url:[url],API);
- const isShowMes=arguments.length===3 && Array.prototype.slice.call(arguments).pop();
- const urlPath= payload && payload.path?this.buildPath(req.url,payload.path):req.url;
- return new Promise((resolve,reject)=>{
- axios({
- url:this.baseURL.concat(urlPath),
- method:req.method.toLowerCase(),
- headers:this.headers,
- data:payload.data || null,
- params:payload.params || null,
- timeout:5000
- }).then(res=>{
- const isError=this.creatErrorMes(res.data);
- if(isError){
- Message({message:res.data.msg,type:'error'});
- }else{
- isShowMes ? Message(this.makeMessage(res.data)):false;
- resolve(res.data);
- }
- })
- })
- }
- // 这里只是简单的用了一下 axios 的 header
- setHeader(config){
- this.headers=merge(this.headers,config)
- }
- // 解析类似 /API/page/2 这样动态参数的问题, 用正则去匹配我们的占位符, 把真实数据放进去
- buildPath(url,path){
- if(!path)return url;
- return url.replace(placeholder,function ($1,$2) {
- return $2=encodeURIComponent(path[$2]);
- });
- }
- // 解析对象为 params 字符串, 以便放入 query 中, 考虑 axios 请求封装了 get 的参数, 这里没用到
- buildUrlParams(url,params){
- if(!params)return url;
- let p=[];
- Object.keys(params).forEach(key=>{
- p.push(`${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`);
- });
- return url += (url.indexOf('?') === -1 ? '?' : '') + p.join('&');
- }
- // 统一设置前端接受数据或操作接口成功会给出的提示
- makeMessage(data){
- const mes={
- message:data.message || "执行成功",
- type:'success'
- };
- if(data.data && (!Object.keys(data.data).length || !data.data.length )){
- mes.mesasge='暂无数据';
- mes.type='warning';
- return mes;
- };
- return mes
- }
- // 创建收集后台代码错误信息并返回, 有错误直接返回 true
- creatErrorMes(data){
- // 收集后台出错的常见字段
- const error=['code','msg'].every(item=>data.hasOwnProperty(item));
- if(!Array.isArray(data)
- && typeof data ==='object'
- && data!==null
- && error){
- return true;
- };
- return false
- }
- }
- // 以插件的形式封装, 挂载到 vue 中
- export function plugin(Vue,fetch){
- if(plugin.installed){
- return
- };
- plugin.installed=true;
- Vue.fetch=fetch;
- Object.defineProperties(Vue.prototype, {
- fetch: {
- get() {
- return fetch
- }
- },
- })
- }
接下来在看一下 API 模块就简单了, 可以按照页面或功能分类去管理接口
- export default {
- login:{
- url:'/xxxx/token',
- method:'post',
- },
- user:{
- info:{
- url:'/xxx/info',
- method:'get'
- },
- page:{
- url:'/xxx/page/{num}'
- method:'get'
- }
- }
- }
使用方法
项目中使用封装的请求可以这样
Vue.use(plugin,new Fetch());
这里展示的是请求 API 对象的一级键值
- this.fetch.commit('login',{
- data:{
- username:'xxx',
- password:'xxx'
- }
- }).then(res=>{
- //do something
- })
如果想请求类似接口中 user 的深层嵌套, 可以这样
- // 这里封装了 prop 方法以方便获取更深层的对象
- this.fetch.commit(['user','info'],{
- params:{
- id:'56',
- }
- },true)// 请求成功后会给出相应的提示
- .then(res=>{
- //do something
- })
再来一个参数放在 path 的
- // 执行完以后完整的 url 为:'/xxx/page/1'
- this.fetch.commit(['user','page'],{
- path:{
- num:'1',// 这里是占位符相应的字段
- },
- params:{
- .... // 附带的参数请求
- }
- })
- .then(res=>{
- //do something
- })
结束
基本思路就是这样, 其实还有很多可以抽离优化的地方, 也有很多设计不满意的, 不过现在基本可以满足日常开发, 后期会不断优化.
PS: 欢迎大家关注我的公众号, 一起加油吧~
qrcode_for_gh_20758ef67f94_258.jpg
来源: http://www.jianshu.com/p/6e7d92d052c0