项目启动
安装项目
// 使用vite安装
yarn create vite my-vue-app --template vue
// 安装插件
yarn
// 启动项目
yarn dev
安装 vue-router
yarn add vue-router@4
官方文档https://router.vuejs.org/zh/
创建/src/router/index.ts
文件
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
const routes: RouteRecordRaw[] = [
{
path: '/',
name: 'home',
component: () => import('../view/home.vue'),
}
]
const router = createRouter({
history: createWebHashHistory(),
routes: routes
})
export default router
修改/src/main.ts
文件
import { createApp } from 'vue'
import App from './App.vue'
import router from '@/router'
const app = createApp(App)
app.use(router)
app.mount('#app')
配置@/xxx
路径引入
安装node
yarn add @types/node -D
修改/tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
"typeRoots" : ["./src/typings"],
"baseUrl": ".", // 默认url
"paths": {
"@/*": ["src/*"] // 路径转换
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}
修改/vite.config.ts
文件
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, './src'),
}
}
})
安装 Ant Design Vue
yarn add ant-design-vue@3.0.0-beta.10
按需引入
修改/src/main.ts
文件
import { createApp } from 'vue'
import App from './App.vue'
import router from '@/router'
import 'ant-design-vue/dist/antd.css';
import antd from 'ant-design-vue';
const app = createApp(App)
app.use(antd)
app.use(router)
app.mount('#app')
解除控制台警告
DevTools 无法加载来源映射:无法加载 http://localhost:3000/antd.css.map 的内容:HTTP 错误:状态代码 404,net::ERR_HTTP_RESPONSE_CODE_FAILURE
打开浏览器控制台,关闭,启动css源代码映射这一项
安装 axios
官方文档https://www.npmjs.com/package/axios
yarn add axios
创建axios实例
创建/src/utils/https.ts
文件
import axios from 'axios'
// 创建axios实例
const service = axios.create({
timeout: 10000, // 如果请求话费了超过 `timeout` 的时间,请求将被中断
headers: { 'Content-type': 'application/json' }, // 即将被发送的自定义请求头
});
export default service
创建请求
创建/src/api/index.ts
文件
import request from '@/utils/https'
export const getUserList = () => {
return request({
url: "/users/user",
method: 'get'
})
}
页面调用
修改/src/view/home.vue
页面
<script lang="ts" setup>
import { getUserList } from '@/api/index'
const getData = async () => {
try {
const res = await getUserList()
console.log(res)
} catch (error) {
console.log(error)
}
}
getData()
</script>
<template></template>
<style lang="scss" scoped></style>
解决跨域问题
修改/vite.config.ts
文件
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, './src'),
}
},
server: {
// 代理服务
proxy: {
'/users': 'http://localhost:8000',
}
}
})
配置方法有一下几种
{
// 字符串简写写法
'/foo': 'http://localhost:4567',
// 选项写法
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
},
// 正则表达式写法
'^/fallback/.*': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/fallback/, '')
},
// 使用 proxy 实例
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
configure: (proxy, options) => {
// proxy 是 'http-proxy' 的实例
}
},
// Proxying websockets or socket.io
'/socket.io': {
target: 'ws://localhost:3000',
ws: true
}
}
配置axios typing
创建/src/typings/axios.d.ts
文件, 加这个文件的好处是,在给request({})
传参的时候会有提示
import * as axios from 'axios';
declare module 'axios' {
interface AxiosInstance {
(config: AxiosRequestConfig): Promise<any>;
}
}
配置axios拦截
修改/src/utils/https.ts
文件
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios'
// 创建axios实例
const service = axios.create({
timeout: 10000, // 如果请求话费了超过 `timeout` 的时间,请求将被中断
headers: { 'Content-type': 'application/json' }, // 即将被发送的自定义请求头
});
// 添加请求拦截器
service.interceptors.request.use((config: AxiosRequestConfig) => {
// 在发送请求之前做些什么
// 通常会在这里对请求头添加token
const token = '111';
if (token) {
config.headers = {
...config.headers,
['Authorization']: `Bearer ${token}`
};
}
return config
}, (error) => {
// 对请求错误做些什么
return Promise.reject(error)
})
// 添加响应拦截器
service.interceptors.response.use((response: AxiosResponse) => {
// 对响应数据做点什么
// 返回响应数据
return Promise.resolve(response.data)
}, (error) => {
// 对响应错误做点什么
// 获取请求报错的错误代码
const type = error.response.request.status
checkStatus(type, error.response.data)
return Promise.reject(error)
})
const checkStatus = (status: number, data: any) => {
// 错误信息处理
}
export default service
安装 mock
官方文档https://www.npmjs.com/package/vite-plugin-mock
yarn add mockjs -D
yarn add @types/mockjs -D
yarn add vite-plugin-mock -D
创建 mock
官方文档https://www.npmjs.com/package/cross-env
创建/src/mock/index.ts
文件
import { MockMethod } from 'vite-plugin-mock'
export default [
{
url: '/api/get',
method: 'get',
response: () => {
return {
code: 0,
data: {
name: 'vben',
},
}
},
},
] as MockMethod[]
创建/src/mockProdServer.ts
文件
import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'
import mock from './mock/index'
export function setupProdMockServer() {
createProdMockServer([ ...mock])
}
修改/src/main.ts
文件
import { createApp } from 'vue'
import App from './App.vue'
import router from '@/router'
import 'ant-design-vue/dist/antd.css';
import antd from 'ant-design-vue';
import { setupProdMockServer } from './mockProdServer';
setupProdMockServer()
const app = createApp(App)
app.use(antd)
app.use(router)
app.mount('#app')
使用 mock
创建/src/api/mock/index.ts
文件
import request from '@/utils/https'
export const getList = () => {
return request({
url: "/api/get",
method: 'get'
})
}
修改/src/view/home.vue
文件
<script lang="ts" setup>
import { getList } from '@/api/mock/index'
const getData = async () => {
try {
const res = await getList()
console.log(res)
} catch (error) {
console.log(error)
}
}
getData()
</script>
<template></template>
<style lang="scss" scoped></style>
配置 mock
完成以上步骤, mock使用会报错, 需要进行配置
修改/vite.config.ts
文件
import { ConfigEnv, UserConfigExport } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
import { viteMockServe } from 'vite-plugin-mock'
// https://vitejs.dev/config/
export default ({ command }: ConfigEnv): UserConfigExport => {
let prodMock = true
return {
plugins: [vue(), viteMockServe({
mockPath: './src/mock',
localEnabled: command === 'serve',
injectCode: `
import { setupProdMockServer } from './mockProdServer';
setupProdMockServer();
`,
})],
resolve: {
alias: {
'@': resolve(__dirname, './src'),
}
},
server: {
proxy: {
'/users': 'http://localhost:8000'
}
}
}
}
mock 环境配置
yarn add cross-env -D
修改/src/package.json
文件
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"dev:mock": "cross-env USE_MOCK=true vite", // mock环境
"preview": "vite preview"
},
启动环境
yarn dev:mock
补充
缺点: mock 环境下启动, 开发环境的接口无法被调用
安装 i18n国际化
官方文档``
yarn add vue-i18n@next
创建 i18n
文件目录
语言文件
// en/index.ts
export default {
header: {
Home: 'home',
}
}
// zh-CN/index.ts
export default {
header: {
Home: '首页',
}
}
注册i18实例, 创建/src/locales/setupI18n.ts
文件
import type { App } from 'vue'
import { createI18n } from 'vue-i18n' //引入vue-i18n组件
import messages from './getMessage'
//注册i8n实例并引入语言文件
const localeData = {
legacy: false, // composition API
locale: 'zh-CN',
messages,
}
export function setupI18n(app: App) {
const i18n = createI18n(localeData);
app.use(i18n);
}
工程化处理/src/locales/getMessage.ts
文件
<!-- 需要安装 lodash-es -->
yarn add @types/lodash-es -D
// 将各种message modules 汇总到这里
import { set } from 'lodash-es';
const modules = import.meta.globEager('./lang/**/*.ts');
interface IObj {
[name: string]: any
}
const genMessage = (langs: Record<string, Record<string, any>>, prefix = 'lang') => {
const obj: IObj = {};
Object.keys(langs).forEach((key) => {
const mod = langs[key].default;
let k = key.replace(`./${prefix}/`, '').replace(/^\.\//, '');
const lastIndex = k.lastIndexOf('.');
k = k.substring(0, lastIndex);
const keyList = k.split('/');
const lang = keyList.shift();
const objKey = keyList.join('.');
if (lang) {
set(obj, lang, obj[lang] || {});
set(obj[lang], objKey, mod);
}
});
return obj;
}
export default genMessage(modules);
自定义 Hook
创建/src/hooks/useI18n.ts
文件
import { i18n } from '@/locales/setupI18n'
export const { t, ...methods } = i18n.global
使用 i18n
<script lang="ts" setup>
import { t } from '@/hooks/useI18n'
</script>
<template>
<div>
{{t('index.header.Home')}}
</div>
</template>
<style lang="scss" scoped></style>
警告
You are running the esm-bundler build of vue-i18n. It is recommended to configure your bundler to explicitly replace feature flag globals with boolean literals to get proper tree-shaking in the final bundle.
解决方法
配置/vite.config.ts
文件
import { ConfigEnv, UserConfigExport } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
import { viteMockServe } from 'vite-plugin-mock'
// https://vitejs.dev/config/
export default ({ command }: ConfigEnv): UserConfigExport => {
return {
plugins: [vue(), viteMockServe({
mockPath: './src/mock',
localEnabled: command === 'serve',
injectCode: `
import { setupProdMockServer } from './mockProdServer';
setupProdMockServer();
`,
})],
resolve: {
alias: {
'@': resolve(__dirname, './src'),
'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js' // 加入这行
}
},
server: {
proxy: {
'/users': 'http://localhost:8000'
}
}
}
}