vue3.0项目搭建初始-技术栈vue3.0+TypeScript+Element-plus+vite+i18n

220 阅读2分钟

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. 常见问题解决

  1. Element Plus样式丢失

    • 检查是否安装了unplugin-vue-components
    • 在main.ts中手动导入样式:import 'element-plus/dist/index.css'
  2. 动态路由刷新后丢失

    • 在页面刷新时重新添加动态路由
    • 使用Pinia持久化插件存储路由信息
  3. i18n切换语言不生效

    typescript

    复制

    // 在组件中使用
    import { useI18n } from 'vue-i18n'
    const { locale } = useI18n()
    // 切换语言
    locale.value = 'en'
    
  4. Axios拦截器中Store未初始化

    • 确保在axios实例创建前已初始化Pinia
    • 使用pinia.state.value直接访问状态