1. 使用Vite创建Vue 3 + TypeScript项目
bash
复制
npm create vite@latest my-vue-app -- --template vue-ts
cd my-vue-app
npm install
2. 安装Element Plus并配置按需导入
bash
复制
npm install element-plus
npm install -D unplugin-vue-components unplugin-auto-import
vite.config.ts:
typescript
复制
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
]
})
3. 安装并配置Pinia状态管理
bash
复制
npm install pinia
main.ts:
typescript
复制
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
app.use(createPinia())
app.mount('#app')
示例store (src/store/user.ts) :
typescript
复制
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
token: '',
username: ''
}),
actions: {
setToken(token: string) {
this.token = token
}
}
})
4. 配置Vue Router及动态路由
bash
复制
npm install vue-router@4
src/router/index.ts:
typescript
复制
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
// 静态路由
export const constantRoutes: RouteRecordRaw[] = [
{
path: '/login',
component: () => import('@/views/Login.vue')
}
]
// 动态路由(需要权限)
export const asyncRoutes: RouteRecordRaw[] = [
{
path: '/dashboard',
component: () => import('@/views/Dashboard.vue'),
meta: { requiresAuth: true }
}
]
const router = createRouter({
history: createWebHistory(),
routes: constantRoutes
})
export default router
导航守卫:
typescript
复制
router.beforeEach(async (to, from, next) => {
const userStore = useUserStore()
// 需要登录且未登录
if (to.meta.requiresAuth && !userStore.token) {
next('/login')
} else {
next()
}
})
5. 集成国际化i18n
bash
复制
npm install vue-i18n@9
src/lang/index.ts:
typescript
复制
import { createI18n } from 'vue-i18n'
import en from './en'
import zh from './zh'
const messages = {
en,
zh
}
export default createI18n({
legacy: false,
locale: 'zh',
fallbackLocale: 'en',
messages
})
语言文件 (src/lang/zh.ts) :
typescript
复制
export default {
welcome: '欢迎使用',
login: '登录'
}
main.ts:
typescript
复制
import i18n from './lang'
app.use(i18n)
6. 封装Axios
bash
复制
npm install axios
src/utils/request.ts:
typescript
复制
import axios from 'axios'
import { useUserStore } from '@/store/user'
const service = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 10000
})
// 请求拦截器
service.interceptors.request.use(config => {
const userStore = useUserStore()
if (userStore.token) {
config.headers.Authorization = `Bearer ${userStore.token}`
}
return config
})
// 响应拦截器
service.interceptors.response.use(
response => response.data,
error => {
if (error.response.status === 401) {
// token过期处理
const userStore = useUserStore()
userStore.setToken('')
window.location.href = '/login'
}
return Promise.reject(error)
}
)
export default service
7. 实现动态路由
在登录后添加路由:
typescript
复制
// 在登录成功后
import router from '@/router'
import { asyncRoutes } from '@/router'
const addRoutes = () => {
asyncRoutes.forEach(route => {
if (!router.hasRoute(route.path)) {
router.addRoute(route)
}
})
// 跳转到首页
router.replace('/dashboard')
}
// 或者从接口获取路由配置
const fetchDynamicRoutes = async () => {
const res = await service.get('/api/routes')
res.data.forEach((route: RouteRecordRaw) => {
router.addRoute(route)
})
}
8. 项目结构建议
复制
src/
├── api/ # 接口模块
├── assets/
├── components/
├── lang/ # 国际化
├── router/ # 路由配置
├── store/ # Pinia store
├── types/ # TS类型定义
├── utils/ # 工具类
├── views/ # 页面组件
├── App.vue
└── main.ts
9. 常见问题解决
-
Element Plus样式丢失:
- 检查是否安装了
unplugin-vue-components - 在main.ts中手动导入样式:
import 'element-plus/dist/index.css'
- 检查是否安装了
-
动态路由刷新后丢失:
- 在页面刷新时重新添加动态路由
- 使用Pinia持久化插件存储路由信息
-
i18n切换语言不生效:
typescript
复制
// 在组件中使用 import { useI18n } from 'vue-i18n' const { locale } = useI18n() // 切换语言 locale.value = 'en' -
Axios拦截器中Store未初始化:
- 确保在axios实例创建前已初始化Pinia
- 使用
pinia.state.value直接访问状态