项目
博客
归档
资源链接
关于我
项目
博客
归档
资源链接
关于我
vue基础搭建参考文档
2025-08-12
·
·
原创
·
·
本文共 1,494个字,预计阅读需要 5分钟。
### 项目初始化 ``` pnpm create vite basic --template vue-ts ``` ### eslint配置 参考:https://www.psvmc.cn/article/2025-05-13-vue3-eslint-prettier.html 依赖 ``` "devDependencies": { "@vue/eslint-config-prettier": "^10.2.0", "@vue/eslint-config-typescript": "^14.5.0", "prettier": "3.5.3", "eslint": "^9.22.0", "eslint-plugin-vue": "~10.0.0", } ``` .prettierrc.json ``` { "$schema": "https://json.schemastore.org/prettierrc", "semi": false, "tabWidth": 2, "singleQuote": true, "printWidth": 100, "trailingComma": "none", "endOfLine": "auto" } ``` eslint.config.ts ``` import { globalIgnores } from 'eslint/config' import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' import pluginVue from 'eslint-plugin-vue' import skipFormatting from '@vue/eslint-config-prettier/skip-formatting' import eslintConfigPrettier from '@vue/eslint-config-prettier' //添加这一行代码 export default defineConfigWithVueTs( { name: 'app/files-to-lint', files: ['**/*.{ts,mts,tsx,vue}'] }, globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**']), pluginVue.configs['flat/essential'], vueTsConfigs.recommended, skipFormatting, eslintConfigPrettier, //添加这一行代码 // 可以自定义配置,例如: { rules: { '@typescript-eslint/no-unused-vars': 0, //允许未使用的变量 '@typescript-eslint/no-explicit-any': 0, //允许使用any类型 '@typescript-eslint/no-unused-expressions': 0, //允许未使用的表达式 'vue/block-lang': 0 //允许使用vue/block-lang } } ) ``` vscode安装插件:安装`Prettier - Code formatter`插件,安装`ESLint`插件 `.vscode/extensions.json` ``` { "recommendations": ["Vue.volar", "esbenp.prettier-vscode", "dbaeumer.vscode-eslint"], } ``` Settings -> 搜索save,找到settings.json文件 ``` { "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[vue]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" }, "editor.formatOnSave": true, "security.workspace.trust.untrustedFiles": "open", "git.enableSmartCommit": true, "explorer.confirmDelete": false, "python.interpreter.infoVisibility": "always", "editor.accessibilitySupport": "off", "workbench.secondarySideBar.defaultVisibility": "hidden", "Lingma.aI Chat.commandAllowlistInAgentMode": "mkdir" } ``` ### 路径配置 安装依赖:`pnpm install @types/node --save-dev` vite.config.ts配置 ```typescript import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' // 配置别名 import path from 'path' // https://vite.dev/config/ export default defineConfig({ plugins: [vue()], resolve: { // 配置别名 alias: { '@': path.resolve(__dirname, 'src') } } }) ``` tsconfig.app.json中配置 ``` "compilerOptions": { .... // 关键配置:添加路径别名映射 "baseUrl": ".", "paths": { "@/*": ["src/*"] } }, .... ``` vue中使用`import HelloWorld from '@/components/HelloWorld.vue'` ### 依赖配置 #### router/pinia ``` "dependencies": { "pinia": "2.3.0", "vue-router": "4.5.0" }, 创建router/index.ts import {router} from "./router" app.user(rounter) 创建stores/index.ts import {createPinia} from 'pinia' const pinia = createPinia() app.use(pinia) ``` #### Tailwind 参考:https://tailwind.nodejs.cn/docs vscode安装插件: **Tailwind CSS IntelliSense** 命令:`pnpm install tailwindcss @tailwindcss/vite` vite.config.ts中配置: ```typescript import { defineConfig } from 'vite' import tailwindcss from '@tailwindcss/vite' export default defineConfig({ plugins: [ tailwindcss(), ], }) ``` 全局的css中style.css引入 ``` @import "tailwindcss"; ``` #### fortawesome 分两套方案: A. **CSS 类名方式**(零 JS,快速上手) B. **官方 Vue 组件方式**(按需打包、Tree-Shaking、支持 Pro 图标) ##### 前置:安装核心依赖 ``` # 方案 A:只想用 CSS 类名 npm i -D @fortawesome/fontawesome-free # 方案 B:想用官方 Vue 组件(推荐) npm i @fortawesome/fontawesome-svg-core \ @fortawesome/vue-fontawesome@latest \ @fortawesome/free-solid-svg-icons \ @fortawesome/free-regular-svg-icons \ @fortawesome/free-brands-svg-icons ``` ##### 方案 A:CSS 类名方式(一行即可) 1. 在入口 `src/main.ts` 引入 CSS: ``` import '@fortawesome/fontawesome-free/css/all.min.css'; ``` 2. 任何地方直接使用类名: ```
``` ##### 方案 B:官方 Vue 组件方式(推荐) ###### 1. 全局注册组件 ``` // src/plugins/fontawesome.ts import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; // 选你需要的图标 import { faHeart, faUser } from '@fortawesome/free-solid-svg-icons'; import { faGithub } from '@fortawesome/free-brands-svg-icons'; library.add(faHeart, faUser, faGithub); export default function install(app: any) { app.component('font-awesome-icon', FontAwesomeIcon); } ``` ``` // src/main.ts import { createApp } from 'vue'; import App from './App.vue'; import installFontAwesome from '@/plugins/fontawesome'; const app = createApp(App); installFontAwesome(app); app.mount('#app'); ``` ###### 2. 在组件中使用 ```
``` ###### 3. 按需 Tree-Shaking(可选) 如果你只用到少量图标,直接 `import { faHeart } from ...` 即可,**Webpack / Vite** 会帮你摇掉没用到的图标,不会整包打包。 Tailwind 控制大小、颜色,Font Awesome 提供图标: ```
下载
``` #### axios+router 安装: npm i axios vue-router@4 目录: ``` src ├─ api // 所有接口按模块拆分 │ ├─ user.ts │ └─ index.ts // 统一导出 ├─ router │ └─ index.ts ├─ stores // 如用 Pinia ├─ utils │ └─ request.ts // Axios 实例 & 拦截器 └─ types └─ api.d.ts ``` 封装 Axios(`utils/request.ts`) ``` import axios from 'axios' import type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosError } from 'axios' import { useRouter } from 'vue-router' // 1️⃣ 使用 InternalAxiosRequestConfig 替代 AxiosRequestConfig const service: AxiosInstance = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, timeout: 10_000 }) // 2️⃣ 拦截器回调里用 InternalAxiosRequestConfig service.interceptors.request.use( (config: InternalAxiosRequestConfig) => { const token = localStorage.getItem('token') if (token) { // 3️⃣ headers 可能为 undefined,需要非空断言 config.headers = config.headers || {} config.headers.Authorization = `Bearer ${token}` } return config }, (error: AxiosError) => Promise.reject(error) ) service.interceptors.response.use( (response: AxiosResponse) => { const { code, data, message } = response.data if (code === 0) return data if (code === 401) { localStorage.removeItem('token') const router = useRouter() router.replace('/login') return Promise.reject(new Error(message || '未登录')) } return Promise.reject(new Error(message || 'Error')) }, (error: AxiosError) => { return Promise.reject(error) } ) export default service ``` 四、接口统一管理(`api/user.ts` 示例) ```typescript import request from '@/utils/request' import type { LoginParams, LoginResult } from '@/types/api' // 登录 export const login = (data: LoginParams) => request.post
('/user/login', data) // 获取用户信息 export const getUserInfo = () => request.get('/user/info') // 刷新 Token(可选) export const refreshToken = () => request.post('/auth/refresh') ``` `api/index.ts` 统一导出: ``` export * from './user' ``` 五、类型声明(`types/api.d.ts`) ```typescript export interface LoginParams { username: string password: string } export interface LoginResult { token: string user: { id: number name: string } } ``` 六、路由配置(`router/index.ts`) ```typescript import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router' import { useAuthStore } from '@/stores/auth' // 如用 Pinia 管理登录态 const routes: RouteRecordRaw[] = [ { path: '/login', name: 'Login', component: () => import('@/views/Login.vue') }, { path: '/', name: 'Layout', component: () => import('@/views/Layout.vue'), meta: { requiresAuth: true }, // 需要鉴权 children: [ { path: 'dashboard', name: 'Dashboard', component: () => import('@/views/Dashboard.vue') } ] }, // 404 { path: '/:pathMatch(.*)*', redirect: '/' } ] const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes }) // ✅ 全局前置守卫 router.beforeEach(async (to, from, next) => { const authStore = useAuthStore() if (to.meta.requiresAuth && !authStore.isLoggedIn) { next('/login') } else { next() } }) export default router ``` 七、Pinia 登录示例(`stores/auth.ts`) ```typescript import { defineStore } from 'pinia' import { login, getUserInfo } from '@/api' export const useAuthStore = defineStore('auth', { state: () => ({ token: localStorage.getItem('token') || '', user: null as null | { id: number; name: string } }), getters: { isLoggedIn: state => !!state.token }, actions: { async login(payload: LoginParams) { const { token, user } = await login(payload) this.token = token this.user = user localStorage.setItem('token', token) }, async fetchUserInfo() { this.user = await getUserInfo() }, logout() { this.token = '' this.user = null localStorage.removeItem('token') } } }) ``` 八、使用示例(`views/Login.vue`) ```
登录
``` 九、环境变量(`.env` 文件) ``` VITE_API_BASE_URL=https://api.example.com ``` | 模块 | 职责 | | ------------------ | -------------------------- | | `utils/request.ts` | 统一实例、拦截器、错误处理 | | `api/*.ts` | 按业务拆分接口、类型安全 | | `router/index.ts` | 全局守卫 + 元信息鉴权 | | `stores/auth.ts` | 登录态、Token 刷新、登出 | | `.env` | 基地址、环境变量 | #### mock ``` src ├─ api │ ├─ user.ts │ └─ index.ts ├─ mock // mock 目录 │ ├─ index.ts // 统一注册 │ └─ user.ts // 业务 mock ├─ utils │ └─ request.ts // 已封装的 axios ├─ .env // 全局变量 ├─ .env.development └─ .env.production ``` 二、环境变量(env 文件) **.env**(公共) ```bash # 占位,会被下面两个文件覆盖 VITE_API_BASE_URL='' ``` **.env.development**(开发) ```bash VITE_API_BASE_URL=/api VITE_USE_MOCK=true ``` **.env.production**(生产) ```bash VITE_API_BASE_URL=https://real-api.xxx.com VITE_USE_MOCK=false ``` ------ 三、安装 mock 工具 ```bash npm i -D vite-plugin-mock@latest mockjs ``` ------ 四、Vite 配置(`vite.config.ts`) ```ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import { viteMockServe } from 'vite-plugin-mock' export default defineConfig(({ command }) => ({ plugins: [ vue(), viteMockServe({ mockPath: 'src/mock', // mock 文件目录 localEnabled: command === 'serve', // dev 时启用 prodEnabled: false // build 时关闭 }) ] })) ``` ------ 五、mock 文件示例 **`src/mock/user.ts`** ```ts import type { MockMethod } from 'vite-plugin-mock' export default [ { url: '/api/user/login', method: 'post', response: ({ body }) => { const { username } = body if (username === 'admin') { return { code: 0, data: { token: 'dev-token-123456', user: { id: 1, name: 'Admin' } } } } return { code: 400, message: '用户名或密码错误' } } }, { url: '/api/user/info', method: 'get', response: () => ({ code: 0, data: { id: 1, name: 'Admin', roles: ['admin'] } }) } ] as MockMethod[] ``` **`src/mock/index.ts`**(集中导出) ```ts import user from './user' export default [...user] ``` ------ 六、Axios 实例自动读取环境变量 把之前 **utils/request.ts** 里的 `baseURL` 改成: ```ts const service = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, timeout: 10_000 }) ``` 无需再改任何代码,开发/生产会自动切换。 ------ 七、验证 1. **开发环境** ```bash npm run dev ``` 打开浏览器,调用 `/api/user/login` 会被 mock 拦截,不走真实服务。 2. **生产环境** ```bash npm run build && npm run preview ``` 所有接口指向 `https://real-api.xxx.com`,mock 自动失效。