# antd-vue3构建后台管理系统 **Repository Path**: zerobit/antd-vue3-tutorials ## Basic Information - **Project Name**: antd-vue3构建后台管理系统 - **Description**: 基于 Ant Design 的 Vue 3 组件库,用于快速构建高质量的后台管理系统指南。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-06-22 - **Last Updated**: 2025-06-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # And-Vue3构建后台管理系统指南 1. 采用Vue3前端技术栈应用 2. 详解 ESLint + Prettier 团队编码规范 3. And-Vue 组件库主题定制&布局搭建 4. 动态路由菜单和权限控制 > 视频参考:【黑马前端Vue3技术栈搭建后台管理系统,Antd-Vue构建后台管理系统,参考字节Arco Pro 最佳实践】 https://www.bilibili.com/video/BV1FD421P7XS/?share_source=copy_web&vd_source=e88e1388cc8fa23f4b6d8fdad446478b ## 一、Vue3项目初始化 Vue3官网:https://cn.vuejs.org/ ### 1.1 初始化Vue3 - 构建Vue3项目 ```bash // npm npm create vue@latest // yarn # For Yarn (v1+) yarn create vue # For Yarn Modern (v2+) yarn create vue@latest # For Yarn ^v4.11 yarn dlx create-vue@latest ``` ![image-20250622112858186](./assets/image-20250622112858186.png) 项目构建完成,可执行以下命令运行项目: ```bash npm install npm run format npm run dev ``` ### 1.2 VS Code 扩展安装 扩展推荐:`.vscode/extensions.json` 输入`@recommended`一键安装推荐拓展 image-20250622115239249 ### 1.3 项目基础代码 1. 删除`src`目录下所有文件 2. 在`src`目录下新建`App.vue`和`main.js` - `App.vue` ```vue ``` - `main.js` ```js import { createApp } from "vue" import App from "./App.vue" const app = createApp(App) app.mount("#app") ``` 3. 开启服务器启动时,自动打开浏览器(可选) `vite.config.js`文件 ```js import { fileURLToPath, URL } from 'node:url' import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import vueDevTools from 'vite-plugin-vue-devtools' // https://vite.dev/config/ export default defineConfig({ plugins: [ vue(), vueDevTools(), ], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) }, }, + server: { + open: true, + }, }) ``` ### 1.4 团队编码规范 `eslant + prettier`配置参考,可根据项目情况定制 - 允许单文件名组件(可选,**新版本已弃用**) 如新建文件`views/Login/index.vue`,结果文件名报错,需配置允许`index.vue`命名。 修改`.eslintrc.cjs`文件 image-20250622122649771 - 统一添加末尾分号(可选) 修改`.prettierrc.json`文件 ```json { "$schema": "https://json.schemastore.org/prettierrc", "semi": false, "singleQuote": true, "printWidth": 100, + "trailingComma": "all", + "endOfLine": "auto" } ``` - VS Code工作区设置 修改`.vscode/setting.json`文件(如无可新建),保存时自动运行eslint ```json { "explorer.fileNesting.enabled": true, "explorer.fileNesting.patterns": { "tsconfig.json": "tsconfig.*.json, env.d.ts", "vite.config.*": "jsconfig*, vitest.config.*, cypress.config.*, playwright.config.*", "package.json": "package-lock.json, pnpm*, .yarnrc*, yarn*, .eslint*, eslint*, .oxlint*, oxlint*, .prettier*, prettier*, .editorconfig" }, + "eslint.enable": true, + "editor.codeActionsOnSave": { + "source.fixAll": "explicit" + }, + "eslint.options": { + "extensions": [ + ".js", + ".vue", + ".jsx", + ".tsx" + ] }, "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" } } ``` ## 二、Ant Design Vue组件库 官方文档:https://www.antdv.com/docs/vue/introduce-cn/ ### 2.1 安装依赖 ```bash # npm npm i --save ant-design-vue@4.x # yarn yarn add ant-design-vue@4.x ``` - 全局完整注册 ```js import { createApp } from 'vue'; import Antd from 'ant-design-vue'; import App from './App'; import 'ant-design-vue/dist/reset.css'; const app = createApp(App); app.use(Antd).mount('#app'); ``` - 自动按需引入 如果你使用的是 `Vite` ,推荐使用 `unplugin-vue-components` ```bash $ npm install unplugin-vue-components -D ``` `vite.config.js` ```js // vite.config.js import { defineConfig } from 'vite'; import Components from 'unplugin-vue-components/vite'; import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'; export default defineConfig({ plugins: [ // ... Components({ resolvers: [ AntDesignVueResolver({ importStyle: false, // css in js }), ], }), ], }); ``` 然后你可以在代码中直接使用 `ant-design-vue` 的组件,插件会自动引入。 ### 2.2 antd 图标库 - 安装依赖 ```bash npm install --save @ant-design/icons-vue ``` - 使用图标 ```vue ``` - 图标全局注册按需导入 1. 新建`src/components/icon/index.js`文件 ```js // 用于把antd icon注册为全局组件 import { StepBackwardOutlined, StepForwardOutlined } from '@ant-design/icons-vue' // 按需要引入 // 注册全局组件,之后需要什么icon写入即可 const icons = [StepBackwardOutlined, StepForwardOutlined] export default { install(app) { icons.forEach((icon) => { app.component(icon.displayName, icon) }) }, } ``` 2. 在`main.js`中全局注册 ```js // 全局引入antd图标 import Icons from '@/components/icon' app.use(Icons) ``` ### 2.3 组件库代码提示配置 配置后,使用antd组件库有代码提示 `jsconfig.json` ```json { "compilerOptions": { + "types": [ + "ant-design-vue/typings/global.d.ts" + ], "paths": { "@/*": ["./src/*"] } }, "exclude": ["node_modules", "dist"] } ``` ### 2.4 antd定制主题和国际化 antd默认主题色是蓝色,默认语言为英文 - 国际化:https://www.antdv.com/docs/vue/i18n-cn - 定制主题:https://www.antdv.com/docs/vue/customize-theme-cn - `ConfigProvider`全局化配置:https://www.antdv.com/components/config-provider-cn **使用方法** 可以在`App.vue`中直接配置 ```vue ``` ## 三、CSS预处理器和全局样式 ### 3.1 安装依赖 考虑到不周的团队习惯,所以把sass和less都安装上,按需使用 ```bash npm install sass less -D ``` ### 3.2 样式全局变量 `styles/var.less` ```less :root { // CSS3变量 --color-primary: #e15536; } ``` `styles/main.less` ```less @import './var.less'; // 全局样式 body { font-size: 14px; color: #333; margin: 0; } a { color: inherit; text-decoration: none; &:hover { color: var(--color-primary); } } h1, h2, h3, h4, h5, h6, p, ul, ol { margin: 0; padding: 0; } // 用于修改nprogress进度条颜色 #nprogress { .bar { background: var(--color-primary) !important; // 自定义颜色 } .peg { box-shadow: 0 0 10px var(--color-primary), 0 0 5px var(--color-primary) !important; } } ``` 在`main.js`中引入全局样式 ```js // 全局样式 import '@/styles/main.less' ``` ## 四、Ant Design Vue布局和项目路由 ### 4.1 antd布局 **src/views/Layout/index.vue** ```vue ``` ### 4.2 项目路由 **src/router/index.js** ```js import { createRouter, createWebHistory } from 'vue-router' const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', name: 'Home', component: () => import('@/views/Layout/index.vue'), }, ], }) export default router ``` 在`main.js`中引入VueRouter ```js // Vue Router import router from '@/router' app.use(router) ``` ### 4.3 在App中使用路由 **App.vue** ```vue ``` ### 4.4 加载进度条、动态设置页面标题和使用环境变量 - 页面加载进度条依赖 ```bash npm install nprogress ``` - 在`src/router/index.js`中配置使用进度条插件及配置动态页面标题 ```js import { createRouter, createWebHistory } from 'vue-router' import NProgress from 'nprogress' import 'nprogress/nprogress.css' NProgress.configure({ showSpinner: false }) const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', name: 'Home', component: () => import('@/views/Layout/index.vue'), meta: { title: '首页' }, }, ], }) // 前置路由守卫 router.beforeEach(() => { // 进度条开始 NProgress.start() }) // 后置路由守卫 router.afterEach((to) => { // 进度条结束 NProgress.done() // 动态设置页面标题 document.title = `${to.meta.title} - ${import.meta.env.VITE_APP_TITLE}` }) export default router ``` - 使用环境变量 - 项目根目录创建`.env.dev`文件 ``` # 开发环境 NODE_ENV='dev' # 为了防止意外地将一些环境变量泄漏到客户端,只有以 VITE_ 为前缀的变量才会暴露给经过 vite 处理的代码。 # js中通过`import.meta.env.VITE_APP_TITLE`取值 VITE_APP_TITLE = 权限管理系统 VITE_APP_PORT = 8080 VITE_APP_BASE_API = '/dev-api' VITE_APP_BASE_FILE_API = '/dev-api/web/api/system/file/upload' # 后端服务地址 VITE_APP_SERVICE_API = 'http://127.0.0.1:9090' ``` - 项目根目录创建`.env.prod`文件 ``` # 开发环境 NODE_ENV='prod' # 为了防止意外地将一些环境变量泄漏到客户端,只有以 VITE_ 为前缀的变量才会暴露给经过 vite 处理的代码。 # js中通过`import.meta.env.VITE_APP_TITLE`取值 VITE_APP_TITLE = 权限管理系统 VITE_APP_PORT = 8080 VITE_APP_BASE_API = '/prod-api' VITE_APP_BASE_FILE_API = '/prod-api/web/api/system/file/upload' # 后端服务地址 VITE_APP_SERVICE_API = 'http://127.0.0.1:9090' ``` - 修改`package.json`文件在项目运行时使用环境变量 ```json "scripts": { "dev": "vite --mode dev", "build": "vite build --mode prod", "prod": "vite --mode prod", "lint": "eslint . --fix", "format": "prettier --write src/" }, ``` - 安装依赖用于获取Node.js的全局变量 ```bash npm install vite-plugin-static-copy --save-dev ``` - `vit.config.js`中进行配置环境 ```js import { fileURLToPath, URL } from 'node:url' import { defineConfig, loadEnv } from 'vite' import vue from '@vitejs/plugin-vue' import vueDevTools from 'vite-plugin-vue-devtools' import Components from 'unplugin-vue-components/vite' import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers' import { viteStaticCopy } from 'vite-plugin-static-copy' // https://vite.dev/config/ export default defineConfig(({ mode }) => { // 获取`.env`环境配置文件 // eslint-disable-next-line no-undef const env = loadEnv(mode, process.cwd()) return { define: { 'process.env': {}, }, plugins: [ vue(), vueDevTools(), viteStaticCopy({ targets: [ { src: '.env*', dest: '', }, ], }), Components({ resolvers: [ AntDesignVueResolver({ importStyle: false, // css in js }), ], }), ], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)), }, }, server: { open: true, host: '0.0.0.0', port: Number(env.VITE_APP_PORT), proxy: { [env.VITE_APP_BASE_API]: { target: env.VITE_APP_SERVICE_API, changeOrigin: true, rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), ''), }, }, }, } }) ``` ## 五、Antd Menu组件基于路由生成菜单 ### 5.1 使用And Menu组件 **src/components/Layout/AppSiderBar.vue** ```vue ``` **src/views/Layout/index.vue** ```vue ``` ### 5.2 路由模块化 - 在`router/modules`目录下给每个功能模块建立路由配置,如下所示: **router/modules/base.js** ```js export default { path: '/base', name: 'Base', component: () => import('@/views/Layout/index.vue'), redirect: '/base/department', meta: { title: '基础管理', icon: 'BarChartOutlined', order: 1 }, children: [ { path: 'department', name: '部门管理', component: () => import('@/views/Base/Department/index.vue'), meta: { title: '部门管理', parent: 'Base' }, }, { path: 'role', name: '角色管理', component: () => import('@/views/Base/Role/index.vue'), meta: { title: '角色管理', parent: 'Base' }, }, { path: 'user', name: '用户管理', component: () => import('@/views/Base/User/index.vue'), meta: { title: '用户管理', parent: 'Base' }, }, ], } ``` - 在`router`目录下新建`asyncRouter.js`文件,用于动态引入所有模块化的路由 ```js // Glob导入: https://cn.vitejs.dev/guide/features#glob-import const modules = import.meta.glob('./modules/*.js', { eager: true }) // 格式化模块 function formatModules(_modules, result) { // 遍历模块 Object.keys(_modules).forEach((key) => { // 获取模块 const defaultModule = _modules[key].default // 模块存在 if (defaultModule) { // 把模块放入结果数组 result.push(defaultModule) } }) // 返回结果数组, 并且按照模块的order属性排序 return result.sort((a, b) => a.meta?.order - b.meta?.order) } // 根据文件生成路由树 export const asyncRoutes = formatModules(modules, []) ``` - 修改`router/index.js`文件动态引入路由 ```js // 引入动态路由 import { asyncRoutes } from './asyncRouter' const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', name: 'Home', component: () => import('@/views/Layout/index.vue'), meta: { title: '首页' }, }, ...asyncRoutes, ], }) ``` ### 5.3 使Menu组件根据路由动态生成菜单 **src/components/Layout/AppSiderBar.vue** ```vue ``` **src/router/index.js** ```js import { createRouter, createWebHistory } from 'vue-router' import NProgress from 'nprogress' import 'nprogress/nprogress.css' NProgress.configure({ showSpinner: false }) // 引入动态路由 import { asyncRoutes } from './asyncRouter' const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', name: 'Home', component: () => import('@/views/Layout/index.vue'), meta: { title: '首页', icon: 'HomeOutlined', order: 0 }, }, { type: 'divider', meta: { title: '分割线' }, }, ...asyncRoutes, ], }) // 前置路由守卫 router.beforeEach(() => { // 进度条开始 NProgress.start() }) // 后置路由守卫 router.afterEach((to) => { // 进度条结束 NProgress.done() // 动态设置页面标题 document.title = `${to.meta.title} - ${import.meta.env.VITE_APP_TITLE}` }) export default router ``` ## 六、权限控制 - 通过==指令==的方式进行权限控制(*例如:按钮权限*) 封装`v-permission`指令,可在组件或原生元素上使用,如: ```html 删除 ``` - 封装`v-permission`指令步骤 1. 编写权限校验指令:**src/permission/index.js** ```js // 从pinia中获取用户的权限列表 // import { usePermissionStore } from '@/store/modules/permission' // 权限校验方法 function checkPermission(el, { value }) { // 获取用户角色 // const { currentRole } = usePermissionStore() const currentRole = 'admin' // 示例先写死 // 传入的权限值要求是一个数组 if (Array.isArray(value) && value.length > 0) { // 判断用户角色是否有权限 const hasPermission = value.includes(currentRole) // 如果没有权限则删除该元素 if (!hasPermission) el.remove() } else { throw new Error(`权限格式错误! 应为 v-permission="['admin','editor']"`) } } export default { mounted(el, binding) { checkPermission(el, binding) }, updated(el, binding) { checkPermission(el, binding) }, } ``` 2. 在`main.js`文件中全局引入权限指令 ```js // 引入权限指令 import permission from '@/permission' app.directive('permission', permission) ```