mirror of
https://github.com/sunniejs/vue-h5-template.git
synced 2026-06-03 18:38:40 +08:00
docs: update docs
This commit is contained in:
parent
8ab84371b4
commit
43058ec878
@ -308,7 +308,7 @@ service.interceptors.request.use(
|
|||||||
// do something with request error
|
// do something with request error
|
||||||
console.log(error); // for debug
|
console.log(error); // for debug
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
// respone拦截器
|
// respone拦截器
|
||||||
service.interceptors.response.use(
|
service.interceptors.response.use(
|
||||||
@ -331,7 +331,7 @@ service.interceptors.response.use(
|
|||||||
Toast.clear();
|
Toast.clear();
|
||||||
console.log("err" + error); // for debug
|
console.log("err" + error); // for debug
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
export default service;
|
export default service;
|
||||||
```
|
```
|
||||||
|
|||||||
@ -30,7 +30,7 @@ service.interceptors.request.use(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (store.getters.token) {
|
if (store.getters.token) {
|
||||||
config.headers["X-Token"] = "";
|
config.headers["X-Token"] = store.getters.token;
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
@ -38,7 +38,7 @@ service.interceptors.request.use(
|
|||||||
// do something with request error
|
// do something with request error
|
||||||
console.log(error); // for debug
|
console.log(error); // for debug
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
// respone拦截器
|
// respone拦截器
|
||||||
service.interceptors.response.use(
|
service.interceptors.response.use(
|
||||||
@ -48,7 +48,7 @@ service.interceptors.response.use(
|
|||||||
if (res.status && res.status !== 200) {
|
if (res.status && res.status !== 200) {
|
||||||
// 登录超时,重新登录
|
// 登录超时,重新登录
|
||||||
if (res.status === 401) {
|
if (res.status === 401) {
|
||||||
store.dispatch("FedLogOut").then(() => {
|
store.dispatch("fedLogOut").then(() => {
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -61,7 +61,7 @@ service.interceptors.response.use(
|
|||||||
Toast.clear();
|
Toast.clear();
|
||||||
console.log("err" + error); // for debug
|
console.log("err" + error); // for debug
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
export default service;
|
export default service;
|
||||||
```
|
```
|
||||||
|
|||||||
@ -6,28 +6,52 @@
|
|||||||
|
|
||||||
前往: [vue.config.js 基础配置](#base)
|
前往: [vue.config.js 基础配置](#base)
|
||||||
|
|
||||||
|
### 路由配置 (router.config.js)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export const constantRouterMap = [
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
component: () => import("@/views/layouts/index"),
|
||||||
|
redirect: "/home",
|
||||||
|
meta: { title: "首页", keepAlive: false },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "/home",
|
||||||
|
name: "Home",
|
||||||
|
component: () => import("@/views/home/index"),
|
||||||
|
meta: { title: "首页", keepAlive: false },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/about",
|
||||||
|
name: "About",
|
||||||
|
component: () => import("@/views/home/about"),
|
||||||
|
meta: { title: "关于我", keepAlive: false },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// 404 catch-all
|
||||||
|
{
|
||||||
|
path: "*",
|
||||||
|
redirect: "/home",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
### 路由实例 (router/index.js)
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import Router from "vue-router";
|
import Router from "vue-router";
|
||||||
|
import { constantRouterMap } from "./router.config.js";
|
||||||
|
|
||||||
Vue.use(Router);
|
Vue.use(Router);
|
||||||
export const router = [
|
|
||||||
{
|
|
||||||
path: "/",
|
|
||||||
name: "index",
|
|
||||||
component: () => import("@/views/home/index"), // 路由懒加载
|
|
||||||
meta: {
|
|
||||||
title: "首页", // 页面标题
|
|
||||||
keepAlive: false, // keep-alive 标识
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const createRouter = () =>
|
const createRouter = () =>
|
||||||
new Router({
|
new Router({
|
||||||
// mode: 'history', // 如果你是 history模式 需要配置 vue.config.js publicPath
|
// mode: 'history', // 如果你是 history模式 需要配置 vue.config.js publicPath
|
||||||
// base: '/app/',
|
|
||||||
scrollBehavior: () => ({ y: 0 }),
|
scrollBehavior: () => ({ y: 0 }),
|
||||||
routes: router,
|
routes: constantRouterMap,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default createRouter();
|
export default createRouter();
|
||||||
|
|||||||
@ -24,7 +24,46 @@ new Vue({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
使用
|
### Store 模块(modules/app.js)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const state = {
|
||||||
|
userName: "",
|
||||||
|
token: "",
|
||||||
|
};
|
||||||
|
const mutations = {
|
||||||
|
SET_USER_NAME(state, name) {
|
||||||
|
state.userName = name;
|
||||||
|
},
|
||||||
|
SET_TOKEN(state, token) {
|
||||||
|
state.token = token;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const actions = {
|
||||||
|
setUserName({ commit }, name) {
|
||||||
|
commit("SET_USER_NAME", name);
|
||||||
|
},
|
||||||
|
// 前端登出
|
||||||
|
fedLogOut({ commit }) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
commit("SET_TOKEN", "");
|
||||||
|
commit("SET_USER_NAME", "");
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Getters
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const getters = {
|
||||||
|
userName: (state) => state.app.userName,
|
||||||
|
token: (state) => state.app.token,
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 使用
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script>
|
<script>
|
||||||
@ -39,7 +78,7 @@ new Vue({
|
|||||||
doDispatch() {
|
doDispatch() {
|
||||||
this.$store.dispatch(
|
this.$store.dispatch(
|
||||||
"setUserName",
|
"setUserName",
|
||||||
"真乖,赶紧关注公众号,组织都在等你~"
|
"真乖,赶紧关注公众号,组织都在等你~",
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -17,15 +17,20 @@ import type {
|
|||||||
InternalAxiosRequestConfig,
|
InternalAxiosRequestConfig,
|
||||||
} from "axios";
|
} from "axios";
|
||||||
import { showToast } from "vant";
|
import { showToast } from "vant";
|
||||||
|
import { useUserStore } from "@/store/modules/user";
|
||||||
|
|
||||||
const service: AxiosInstance = axios.create({
|
const service: AxiosInstance = axios.create({
|
||||||
baseURL: import.meta.env.VITE_API_BASE_URL || "",
|
baseURL: import.meta.env.VITE_API_BASE_URL || "",
|
||||||
withCredentials: false,
|
withCredentials: false,
|
||||||
timeout: 10000,
|
timeout: 15000,
|
||||||
});
|
});
|
||||||
|
|
||||||
service.interceptors.request.use(
|
service.interceptors.request.use(
|
||||||
(config: InternalAxiosRequestConfig) => {
|
(config: InternalAxiosRequestConfig) => {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
if (userStore.token) {
|
||||||
|
config.headers.Authorization = `Bearer ${userStore.token}`;
|
||||||
|
}
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
(error: AxiosError) => {
|
(error: AxiosError) => {
|
||||||
@ -37,15 +42,22 @@ service.interceptors.response.use(
|
|||||||
(response: AxiosResponse) => {
|
(response: AxiosResponse) => {
|
||||||
const res = response.data;
|
const res = response.data;
|
||||||
if (res.code !== 200) {
|
if (res.code !== 200) {
|
||||||
showToast(res.msg);
|
showToast(res.msg || "Error");
|
||||||
return Promise.reject(res.msg || "Error");
|
return Promise.reject(new Error(res.msg || "Error"));
|
||||||
} else {
|
|
||||||
return res.data;
|
|
||||||
}
|
}
|
||||||
|
return res.data;
|
||||||
},
|
},
|
||||||
(error: AxiosError) => {
|
(error: AxiosError) => {
|
||||||
showToast(error.message);
|
const status = error.response?.status;
|
||||||
return Promise.reject(error.message);
|
if (status === 401) {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
userStore.$reset();
|
||||||
|
window.location.hash = "#/login";
|
||||||
|
}
|
||||||
|
const message =
|
||||||
|
(error.response?.data as any)?.msg || error.message || "Network Error";
|
||||||
|
showToast(message);
|
||||||
|
return Promise.reject(error);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -75,26 +87,31 @@ export const http = {
|
|||||||
export default service;
|
export default service;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 主要特点
|
||||||
|
|
||||||
|
- **请求拦截器**:自动从 Pinia store 注入 `Authorization` token
|
||||||
|
- **响应拦截器**:统一处理业务错误码和 HTTP 错误
|
||||||
|
- **401 处理**:自动清除登录态并跳转登录页
|
||||||
|
- **泛型支持**:`http.get<UserInfo>(url)` 获得正确的类型推导
|
||||||
|
|
||||||
## useFetchApi 封装
|
## useFetchApi 封装
|
||||||
|
|
||||||
项目同时提供了基于 `@vueuse/core` 的 `createFetch` 封装,支持响应式的请求:
|
项目同时提供了基于 `@vueuse/core` 的 `createFetch` 封装,支持响应式的请求:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { createFetch } from "@vueuse/core";
|
import { createFetch } from "@vueuse/core";
|
||||||
import { useCookies } from "@vueuse/integrations/useCookies";
|
|
||||||
import { showNotify } from "vant";
|
import { showNotify } from "vant";
|
||||||
|
import { useUserStore } from "@/store/modules/user";
|
||||||
|
|
||||||
const useFetchApi = createFetch({
|
const useFetchApi = createFetch({
|
||||||
baseUrl: "",
|
baseUrl: "",
|
||||||
options: {
|
options: {
|
||||||
async beforeFetch({ options }) {
|
async beforeFetch({ options }) {
|
||||||
const myToken =
|
const userStore = useUserStore();
|
||||||
useCookies().get(
|
const token = userStore.token || "";
|
||||||
(import.meta.env.VITE_TOKEN_KEY as string) || "Authorization",
|
|
||||||
) || "";
|
|
||||||
options.headers = {
|
options.headers = {
|
||||||
...options.headers,
|
...options.headers,
|
||||||
Authorization: `Bearer ${myToken}`,
|
Authorization: `Bearer ${token}`,
|
||||||
};
|
};
|
||||||
return { options };
|
return { options };
|
||||||
},
|
},
|
||||||
@ -108,6 +125,8 @@ const useFetchApi = createFetch({
|
|||||||
export default useFetchApi;
|
export default useFetchApi;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> 两种请求方案均统一从 Pinia `useUserStore` 获取 token,保持认证策略一致。
|
||||||
|
|
||||||
## 接口管理
|
## 接口管理
|
||||||
|
|
||||||
在 `src/api/index.ts` 中统一管理接口:
|
在 `src/api/index.ts` 中统一管理接口:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user