本文将实如今 Vue
框架中使用 Typescript
+ Element-ui
以单例模式个性化封装 Axios
, 知足咱们项目的所需,留个赞再走吧vue
typescript 是 JavaScript 的强类型版本。而后在编译期去掉类型和特有语法,生成纯粹的 JavaScript 代码。因为最终在浏览器中运行的仍然是 JavaScript,因此 TypeScript 并不依赖于浏览器的支持,也并不会带来兼容性问题。node
TypeScript 是 JavaScript 的超集,这意味着他支持全部的 JavaScript 语法。并在此之上对 JavaScript 添加了一些扩展,如 class / interface / module 等。这样会大大提高代码的可阅读性。ios
与此同时,TypeScript 也是 JavaScript ES6 的超集,Google 的 Angular 2.0 也宣布采用 TypeScript 进行开发。这更是充分说明了这是一门面向将来而且脚踏实地的语言。sql
下面咱们列出了缘由,为何咱们应该拥抱TypeScript:typescript
强类型语言的优点在于静态类型检查。归纳来讲主要包括如下几点:数据库
Axios 是一个基于 promise 的 HTTP 库,能够用在浏览器和 node.js 中。npm
// 为给定 ID 的 user 建立请求
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 上面的请求也能够这样作
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
复制代码
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
复制代码
为方便起见,为全部支持的请求方法提供了别名编程
咱们大体了解了 Axios 以及一些经常使用的方法, 那接下来咱们就开始进入正题吧element-ui
$ vue create my-vue-typescript
复制代码
上下键选择,空格键肯定json
接下来是一些常规选项
下面是询问要不要记录此次配置以便后面直接使用,咱们选择y
Utils
文件夹以及 咱们今天的主角 request.ts
文件Element-ui
$ npm i element-ui -S
复制代码
qs
$ npm i qs -S
复制代码
qs 是一个增长了一些安全性的查询字符串解析和序列化字符串的库
Axios
$ npm i axios -S
复制代码
在此我不会为你们讲解太多 Ts 的知识,但在开始以前想让你们明白 Typescript
中的几个点,否则无法继续下去
TypeScript里的类型注解是一种轻量级的为函数或变量添加约束的方式
# 咱们指定了 hello 这个变量必须是 string 类型
const hello: string = 'Hello World'
# 咱们指定了 greeter 传入的 person 参数必须是 string 类型
function greeter(person: string) {
return "Hello, " + person;
}
复制代码
在TypeScript里,只在两个类型内部的结构兼容那么这两个类型就是兼容的。 这就容许咱们在实现接口时候只要保证包含了接口要求的结构就能够,而没必要明确地使用 implements语句
interface IFamilyData {
father: string
mom: string
son: string
}
function getFamily(family: IFamilyData) {
return `爸爸${family.father},妈妈${family.mom},儿子${family.son}`
}
const family = { father: 'Jack', mom: 'Ruth', son: 'Bieber' }
document.body.innerHTML = getFamily(family)
复制代码
TypeScript支持JavaScript的新特性,好比支持基于类的面向对象编程
class Person{
// 增长两个属性
name:string
age:number
// 增长能够传参的构造方法
constructor(name:string,age:number){
this.name = name
this.age = age
}
// 增长一个自定义的普通的打印函数
print(){
return this.name + ':'' + this.age
}
// 使用上面建立的类
// var p = new Person() // 这里在使用上面的类时没有传递参数是会报错的,由于上面定义的 constructor 构造方法中存在参数,因此这里也必定要传递参数
var p = new Person('xiaochuan',22)
alert(p.print())
}
复制代码
最先接触单例模式是在学 PHP
的时候,那个时候在尚未使用框架 PHP 引入 Mysql 的时候,我都会把 Mysql 封装为一个单例模式的类
单例模式(Singleton),也叫单子模式,是一种经常使用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只须要拥有一个的全局对象,这样有利于咱们协调系统总体的行为。好比在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,而后服务进程中的其余对象再经过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理
单例模式只容许建立一个对象,所以节省内存,加快对象访问速度,所以对象须要被公用的场合适合使用,如多个模块使用同一个数据源链接对象等等。如:
一个类能返回对象一个引用(永远是同一个)和一个得到该实例的方法(必须是静态方法,一般使用getInstance这个名 称);当咱们调用这个方法时,若是类持有的引用不为空就返回这个引用,若是类保持的引用为空就建立该类的实例并将实例的引用赋予该类保持的引用;同时咱们 还将该类的构造函数定义为私有方法,这样其余处的代码就没法经过调用该类的构造函数来实例化该类的对象,只有经过该类提供的静态方法来获得该类的惟一实例
# public 公开的
# protected 受保护的
# private 私有的
import http from 'http'
import https from 'https'
import axios, { AxiosResponse, AxiosRequestConfig, CancelTokenStatic } from 'axios'
import { Message, MessageBox } from 'element-ui'
import qs from 'qs'
import { UserModule } from '@/store/modules/user'
// 类名
class Request {
// 属性
protected baseURL: any = process.env.VUE_APP_BASE_API
protected service: any
protected pending: Array<{
url: string,
cancel: Function
}> = []
protected CancelToken: CancelTokenStatic = axios.CancelToken
protected axiosRequestConfig: AxiosRequestConfig = {}
protected successCode: Array<Number> = [200, 201, 204]
private static _instance: Request;
// 构造函数 初始化工做
private constructor() {
}
// 惟一实例
public static getInstance() : Request {}
protected requestConfig(): void {}
protected interceptorsRequest() {}
protected interceptorsResponse(): void {}
protected removePending(config: any): void {}
public async post(url: string, data: any = {}, config: object = {}) {}
public async delete(url: string, config: object = {}) {}
public async put(url: string, data: any = {}, config: object = {}) {}
public async get(url: string, params: any = {}, config: object = {}) {}
protected requestLog(request: any): void {}
protected responseLog(response: any): void {}
}
export default Request.getInstance()
复制代码
requestConfig
从名字上咱们就看的出来这是一个关于配置的方法 小提示: void 表示没有返回值
protected requestConfig(): void {
this.axiosRequestConfig = {
// baseURL`将自动加在 `url` 前面,除非 `url` 是一个绝对 URL
baseURL: this.baseURL,
// `headers` 是即将被发送的自定义请求头
headers: {
timestamp: new Date().getTime(),
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
},
// transformRequest` 容许在向服务器发送前,修改请求数据
transformRequest: [function (data: any) {
//对data进行任意转换处理
return data;
}],
// `transformResponse` 在传递给 then/catch 前,容许修改响应数据
transformResponse: [function(data: AxiosResponse) {
return data
}],
// `paramsSerializer` 是一个负责 `params` 序列化的函数
paramsSerializer: function(params: any) {
return qs.stringify(params, { arrayFormat: 'brackets' })
},
// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
// 若是请求话费了超过 `timeout` 的时间,请求将被中断
timeout: 30000,
// `withCredentials` 表示跨域请求时是否须要使用凭证
withCredentials: false,
// `responseType` 表示服务器响应的数据类型,能够是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
responseType: 'json',
// `xsrfCookieName` 是用做 xsrf token 的值的cookie的名称
xsrfCookieName: 'XSRF-TOKEN',
// `xsrfHeaderName` 是承载 xsrf token 的值的 HTTP 头的名称
xsrfHeaderName: 'X-XSRF-TOKEN',
// `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
maxRedirects: 5,
// `maxContentLength` 定义容许的响应内容的最大尺寸
maxContentLength: 2000,
// `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject promise 。若是 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 不然,promise 将被 rejecte
validateStatus: function(status: number) {
return status >= 200 && status < 300
},
// `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。容许像这样配置选项:
// `keepAlive` 默认没有启用
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true })
}
}
复制代码
interceptorsRequest
protected interceptorsRequest() {
this.service.interceptors.request.use(
(config: any) => {
if (UserModule.token) {
config.headers['authorization'] = UserModule.token
}
return config
},
(error: any) => {
return Promise.reject(error)
}
)
}
复制代码
protected interceptorsResponse(): void {
this.service.interceptors.response.use(
(response: any) => {
if (this.successCode.indexOf(response.status) === -1) {
Message({
message: response.data.message || 'Error',
type: 'error',
duration: 5 * 1000
})
if (response.data.code === 401) {
MessageBox.confirm(
'你已被登出,能够取消继续留在该页面,或者从新登陆',
'肯定登出',
{
confirmButtonText: '从新登陆',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
UserModule.ResetToken()
location.reload()
})
}
return Promise.reject(new Error(response.message || 'Error'))
} else {
return response.data
}
},
(error: any) => {
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
}
复制代码
removePending
protected removePending(config: any): void {
for (let p in this.pending) {
let item: any = p
let list: any = this.pending[p]
if (list.url === `${config.url}/${JSON.stringify(config.data)}&request_type=${config.method}`) {
list.cancel()
this.pending.splice(item, 1)
}
}
}
复制代码
responseLog
protected responseLog(response: any): void {
if (process.env.NODE_ENV === 'development') {
const randomColor = `rgba(${Math.round(Math.random() * 255)},${Math.round( Math.random() * 255 )},${Math.round(Math.random() * 255)})`
console.log(
'%c┍------------------------------------------------------------------┑',
`color:${randomColor};`
)
console.log('| 请求地址:', response.config.url)
console.log('| 请求参数:', qs.parse(response.config.data))
console.log('| 返回数据:', response.data)
console.log(
'%c┕------------------------------------------------------------------┙',
`color:${randomColor};`
)
}
}
复制代码
public async post(url: string, data: any = {}, config: object = {}) {
try {
const result = await this.service.post(url, qs.stringify(data), config)
return result.data
} catch (error) {
console.error(error)
}
}
public async delete(url: string, config: object = {}) {
try {
await this.service.delete(url, config)
} catch (error) {
console.error(error)
}
}
...
复制代码
import http from 'http'
import https from 'https'
import axios, { AxiosResponse, AxiosRequestConfig, CancelTokenStatic } from 'axios'
import { Message, MessageBox } from 'element-ui'
import qs from 'qs'
import { UserModule } from '@/store/modules/user'
class Request {
protected baseURL: any = process.env.VUE_APP_BASE_API
protected service: any = axios
protected pending: Array<{
url: string,
cancel: Function
}> = []
protected CancelToken: CancelTokenStatic = axios.CancelToken
protected axiosRequestConfig: AxiosRequestConfig = {}
protected successCode: Array<Number> = [200, 201, 204]
private static _instance: Request;
constructor() {
this.requestConfig()
this.service = axios.create(this.axiosRequestConfig)
this.interceptorsRequest()
this.interceptorsResponse()
}
public static getInstance() : Request {
// 若是 instance 是一个实例 直接返回, 若是不是 实例化后返回
this._instance || (this._instance = new Request())
return this._instance
}
protected requestConfig(): void {
this.axiosRequestConfig = {
baseURL: this.baseURL,
headers: {
timestamp: new Date().getTime(),
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
},
transformRequest: [obj => qs.stringify(obj)],
transformResponse: [function(data: AxiosResponse) {
return data
}],
paramsSerializer: function(params: any) {
return qs.stringify(params, { arrayFormat: 'brackets' })
},
timeout: 30000,
withCredentials: false,
responseType: 'json',
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxRedirects: 5,
maxContentLength: 2000,
validateStatus: function(status: number) {
return status >= 200 && status < 500
},
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true })
}
}
protected interceptorsRequest() {
this.service.interceptors.request.use(
(config: any) => {
this.removePending(config)
config.CancelToken = new this.CancelToken((c: any) => {
this.pending.push({ url: `${config.url}/${JSON.stringify(config.data)}&request_type=${config.method}`, cancel: c })
})
if (UserModule.token) {
config.headers['authorization'] = UserModule.token
}
this.requestLog(config)
return config
},
(error: any) => {
return Promise.reject(error)
}
)
}
protected interceptorsResponse(): void {
this.service.interceptors.response.use(
(response: any) => {
this.responseLog(response)
this.removePending(response.config)
if (this.successCode.indexOf(response.status) === -1) {
Message({
message: response.data.message || 'Error',
type: 'error',
duration: 5 * 1000
})
if (response.data.code === 401) {
MessageBox.confirm(
'你已被登出,能够取消继续留在该页面,或者从新登陆',
'肯定登出',
{
confirmButtonText: '从新登陆',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
UserModule.ResetToken()
location.reload()
})
}
return Promise.reject(new Error(response.message || 'Error'))
} else {
return response.data
}
},
(error: any) => {
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
}
protected removePending(config: any): void {
for (let p in this.pending) {
let item: any = p
let list: any = this.pending[p]
if (list.url === `${config.url}/${JSON.stringify(config.data)}&request_type=${config.method}`) {
list.cancel()
console.log('=====', this.pending)
this.pending.splice(item, 1)
console.log('+++++', this.pending)
}
}
}
public async post(url: string, data: any = {}, config: object = {}) {
try {
const result = await this.service.post(url, qs.stringify(data), config)
return result.data
} catch (error) {
console.error(error)
}
}
public async delete(url: string, config: object = {}) {
try {
await this.service.delete(url, config)
} catch (error) {
console.error(error)
}
}
public async put(url: string, data: any = {}, config: object = {}) {
try {
await this.service.put(url, qs.stringify(data), config)
} catch (error) {
console.error(error)
}
}
public async get(url: string, parmas: any = {}, config: object = {}) {
try {
await this.service.get(url, parmas, config)
} catch (error) {
console.error(error)
}
}
protected requestLog(request: any): void {
}
protected responseLog(response: any): void {
if (process.env.NODE_ENV === 'development') {
const randomColor = `rgba(${Math.round(Math.random() * 255)},${Math.round( Math.random() * 255 )},${Math.round(Math.random() * 255)})`
console.log(
'%c┍------------------------------------------------------------------┑',
`color:${randomColor};`
)
console.log('| 请求地址:', response.config.url)
console.log('| 请求参数:', qs.parse(response.config.data))
console.log('| 返回数据:', response.data)
console.log(
'%c┕------------------------------------------------------------------┙',
`color:${randomColor};`
)
}
}
}
export default Request.getInstance()
复制代码
import Request from '@/utils/request'
import { ADMIN_LOGIN_API, ADMIN_USER_INFO_API } from '@/api/interface'
interface ILoginData {
username: string
password: string
}
export const login = (params: ILoginData) => Request.post(ADMIN_LOGIN_API, params)
export const getUserInfo = () => Request.get(ADMIN_USER_INFO_API)
复制代码
各位大哥大姐留个赞吧 O(∩_∩)O哈哈~ 到此就结束了,我也是第一次学习 ts 而且 封装 axios 写的很差,下方留言指出,谢谢。