前言我们要注意区分 axios 和 ajax :
ajax 是一种技术统称,技术内容包括:html 或 xhtml, css, javascript, dom, xml, xslt, 以及最重要的xmlhttprequest,用于浏览器与服务器之间使用异步数据传输(http 请求),做到局部请求以实现局部刷新,使用是基于 xmlhttprequest 进行使用;
axios 是 一个基于 promise 的 http 库,是一个是第三方库
主要技术栈:vue3,ts,axios,mock.js,elementplus
一、axios 的依赖安装与处理 1. 依赖安装使用异步网络请求肯定离不开loading、message 等提示,今天我们配合 elementplus 一起使用;
// 安装axios npm install axios --save // 安装 elementplusnpm install element-plus --save
2. 全局 axios 封装 src 目录下 utils 目录下,新建 request.ts,因为使用的是ts,需要提前定义数据格式:
定义请求数据返回的格式,需要提前确认好
定义 axios 基础配置信息
请求拦截器:所有请求最先到达的地方,我们可以在此自定义请求头信息(比如:token、多语言等等)
响应拦截器:返回数据最先到达的地方,我们可以在此处理异常信息(比如:code为401重定向至登录、code为500提示错误信息)
import axios, { axiosinstance, axioserror, axiosrequestconfig, axiosresponse } from "axios";import { elmessage, elloading, elmessagebox } from "element-plus"; // response interface { code, msg, success }// 不含 datainterface result { code: number, success: boolean, msg: string} // request interface,包含 datainterface resultdata<t = any> extends result { data?: t} enum requestenums { timeout = 10000, // 请求超时 request timeout fail = 500, // 服务器异常 server error logintimeout = 401, // 登录超时 login timeout success = 200, // 请求成功 request successfully} // axios 基础配置const config = { // 默认地址,可以使用 process node内置的,项目根目录下新建 .env.development baseurl: process.env.vue_app_base_api as string, timeout: requestenums.timeout as number, // 请求超时时间 withcredentials: true, // 跨越的时候允许携带凭证} class request { service: axiosinstance; constructor(config: axiosrequestconfig) { // 实例化 serice this.service = axios.create(config); /** * 请求拦截器 * request -> { 请求拦截器 } -> server */ this.service.interceptors.request.use( (config: axiosrequestconfig) => { const token = localstorage.getitem('token') ''; return { ...config, headers: { 'customtoken': "custombearer " + token } } }, (error: axioserror) => { // 请求报错 promise.reject(error) } ); /** * 响应拦截器 * response -> { 响应拦截器 } -> client */ this.service.interceptors.response.use( (response: axiosresponse) => { const { data, config } = response; if (data.code === requestenums.logintimeout) { // 表示登录过期,需要重定向至登录页面 elmessagebox.alert("session expired", "system info", { confirmbuttontext: 'relogin', type: 'warning' }).then(() => { // 或者调用 logout 方法去处理 localstorage.setitem('token', ''); location.href = '/' }) } if (data.code && data.code !== requestenums.success) { elmessage.error(data); return promise.reject(data); } return data }, (error: axioserror) => { const { response } = error; if (response) { this.handlecode(response.status); } if (!window.navigator.online) { elmessage.error("网络连接失败,请检查网络"); // 可以重定向至404页面 } } ) } public handlecode = (code: number): void => { switch (code) { case 401: elmessage.error("登陆失败,请重新登录"); break; case 500: elmessage.error("请求异常,请联系管理员"); break; default: elmessage.error('请求失败'); break; } } // 通用方法封装 get<t>(url: string, params?: object): promise<resultdata<t>> { return this.service.get(url, { params }); } post<t>(url: string, params?: object): promise<resultdata<t>> { return this.service.post(url, params); } put<t>(url: string, params?: object): promise<resultdata<t>> { return this.service.put(url, params); } delete<t>(url: string, params?: object): promise<resultdata<t>> { return this.service.delete(url, { params }); }} export default new request(config)
3. 实际使用src 目录下新增 api/index.ts
定义请求的参数类型
定义响应想具体参数类型
这里我们使用到ts 中的 namespace ,实际开发中我们很多 api 可能会出现相同名字不同含义,所以我们使用 namespace 进行定义
import request from "@/utils/request"; namespace user { // login export interface loginform { username: string, password: string }} export namespace system { export interface info { path: string, routename: string } export interface responseitem { code: number, items: array<sidebar>, success: boolean } export interface sidebar { id: number, hashid: string | number, title: string, routename: string, children: array<sidebaritem>, } export interface sidebaritem { id: number, parentid: number, hashid: string | number, title: string, }} export const info = (params: system.info) => { // response if (!params || !params.path) throw new error('params and params in path can not empty!') // 这里因为是全局的一个info,根据路由地址去请求侧边栏,所需不用把地址写死 return request.post<system.sidebar>(params.path, { routename: params.routename })}
vue 文件中调用
<script lang="ts" setup name="sidebar">import { ref, reactive, onbeforemount } from "vue"import { info } from "@/api"import { useroute } from "vue-router"const route = useroute(); let loading = ref<boolean>(false);let sidebar = ref<any>({}); const _fetch = async (): promise<void> => { const routename = route.name as string; const path = '/' + routename.replace(routename[0], routename[0].tolocalelowercase()) + 'info' try { loading.value = true; const res = await info({ path, routename }); if (!res || !res.data) return; sidebar.value = res.data; } finally { loading.value = false }} onbeforemount(() => { _fetch();}) </script>
二、 mock.js 的依赖安装与处理 1. 安装依赖# 安装npm install mockjs --save
在 ts 中使用时,我们需要现在 shims-vue.d.ts 文件中去抛出模块,不然会出现引入报错的问题
/* eslint-disable */declare module '*.vue' { import type { definecomponent } from 'vue' const component: definecomponent<{}, {}, any> export default component} declare module 'mockjs';
2. 新建 mock 所需的文件
index.ts(属于mockjs全局配置文件),mockjs/javascript/index.ts(具体的数据文件),这两个需要关注,别的不用关注
1. 新建 mockjs/javascript/index.ts(具体的数据文件)
因为我这里的数据主要是 侧边栏的数据,都是固定好的,所以并没有用到 mockjs 的规则生成数据
import { globalsidebar, sidebar } from "../../sidebar"; namespace infosidebar { export type infosidebarparams = { body: string, type: string, url: string }} const datasource: array<globalsidebar> = [ { maintitle: 'javascript基础问题梳理', mainsidebar: [ { id: 0, hashid: 'this', title: 'this指向', routename: 'jsbasic', children: [ { id: 1, parentid: 0, hashid: 'globalfunction', title: '全局函数' }, { id: 2, parentid: 0, hashid: 'objectmethod', title: '对象方法' }, { id: 3, parentid: 0, hashid: 'constructor', title: '构造函数' }, { id: 4, parentid: 0, hashid: 'settimeout', title: '定时器、回调函数' }, { id: 5, parentid: 0, hashid: 'eventfunction', title: '事件函数' }, { id: 6, parentid: 0, hashid: 'arrowfunction', title: '箭头函数' }, { id: 7, parentid: 0, hashid: 'callapplybind', title: 'call、apply、bind' }, ] }, { id: 2, hashid: 'deepclone', title: '深拷贝和浅拷贝', routename: 'jsbasic', children: [] } ] },]; export default { name: 'jsbasicinfo', jsbasicinfo(params: infosidebar.infosidebarparams) { const param = json.parse(params.body) if (!param) throw new error("params can not empty!"); const data = datasource.find((t: globalsidebar) => { return t.mainsidebar.filter((x: sidebar) => { return x.routename === param.routename }) }) return { data, success: true, code: 200 } }}
sidebar.ts
/** * @param { number } id unique value * @param { string } hashid href unique value * @param { string } title show current title * @param { string } routename page find data */ interface globalsidebar { maintitle: string, mainsidebar: array<sidebar>} interface sidebar { id: number, hashid: string | number, title: string, routename: string, children: array<sidebaritem>,} interface sidebaritem { id: number, parentid: number, hashid: string | number, title: string,} export { globalsidebar, sidebar, sidebaritem}
2. 新建 mockjs/index.ts
import mock from "mockjs";import jsbasicinfo from "./tpl/javascript/index";const requestmethod = 'post';const base_url = process.env.vue_app_base_api;const mocks = [jsbasicinfo]; for (let i of mocks) { mock.mock(base_url + '/' + i.name, requestmethod, i.jsbasicinfo);} export default mock
3. main.ts 引入
import { createapp } from 'vue'import app from './app.vue' if(process.env.node_env == 'development'){ require('./mockjs/index')} const app = createapp(app);app.mount('#app');
三、结合使用实际上就是刚刚调用axios 的那一段代码
<script lang="ts" setup name="sidebar">import { ref, reactive, onbeforemount } from "vue"import { info } from "@/api"import { useroute } from "vue-router"const route = useroute(); let loading = ref<boolean>(false);let sidebar = ref<any>({}); const _fetch = async (): promise<void> => { const routename = route.name as string; const path = '/' + routename.replace(routename[0], routename[0].tolocalelowercase()) + 'info' try { loading.value = true; const res = await info({ path, routename }); if (!res || !res.data) return; sidebar.value = res.data; } finally { loading.value = false }} onbeforemount(() => { _fetch();}) </script>
以上就是vue3和ts封装axios及使用mock.js的方法是什么的详细内容。