完整项目地址 文章更新日期: 2023-08-08 放心食用
计划系列文章:
- 用 Vue3+Vite 实现一个后台管理系统(基础搭建)
- 用 Vue3+Vite 实现一个后台管理系统(登录架构)
- 用 Vue3+Vite 实现一个后台管理系统(Layout 架构)
- 用 Vue3+Vite 实现一个后台管理系统(通用功能封装)
- 用 Vue3+Vite 实现一个后台管理系统(权限处理)
- 用 Vue3+Vite 实现一个后台管理系统(动态表格和列表拖拽)
- 用 Vue3+Vite 实现一个后台管理系统(富文本和 markdown)
- 其他(动态换肤,自定义前缀,全局配置等)
1. 初始化项目
1.1 使用 vite 创建项目
# npm
npm create vite@latest
# yarn
yarn create vite
# pnpm
pnpm create vite
选择配置(默认安装: VueRouter 丶 Pinia 丶 ESLint 丶 Prettier)
✔ Project name(项目名): project-vue3
? Select a framework: » - Use arrow-keys. Return to submit.
Vanilla
> Vue
React
Preact
Lit
Svelte
Others
? Select a variant: » - Use arrow-keys. Return to submit.
JavaScript
TypeScript
> Customize with create-vue ↗
Nuxt ↗
✔ Add TypeScript ?(添加TS) : No
✔ Add JSX Support ?(添加JSX支持) : No
✔ Add Vue Router for Single Page Application development ?(添加Vue-router) : Yes
✔ Add Pinia for state management ?(添加状态管理Pinia) : Yes
✔ Add Vitest for Unit testing(为单元测试添加Vitest)? : No
✔ Add an End-to-End Testing Solution ?(添加端到端测试解决方案 No / Cypress / Playwright) : No
✔ Add ESLint for code quality(为代码质量添加ESLint)? : Yes
✔ Add Prettier for code formatting(为代码格式添加Prettier)? : Yes
Scaffolding project in ./tooldog...
Done.
1.2 重构无用内容
1.21) 删除无用文件
- 删除
views下所有文件 - 删除
stores下所有文件 - 删除
components下所有文件 - 删除
assets下所有文件
1.22) 重构内容
- 在
views文件夹下新建dashboard/analysis/index.vue文件:
<template>
<div>分析页</div>
</template>
- 修改
router/index.js路由文件(把删掉页面的路由干掉,加上HomeView.vue页面路由)
import { createRouter, createWebHistory } from 'vue-router'
// 公共路由表
const publicRoutes = [
{
path: '/',
name: 'analysis',
component: () => import('@/views/dashboard/analysis/index.vue')
}
]
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: publicRoutes
})
export default router
- 修改项目根组件
App.vue的内容(把无用的删了,只留下面内容即可)
<script setup>
import { RouterView } from 'vue-router'
</script>
<template>
<RouterView />
</template>
- 在
main.js删除示例样式
// 删除掉,css文件已经删除过了
import './assets/main.css'
ok,处理好之后我们就会得到一个很干净的项目了,如果你的步骤和我一致,目前的文件目录应该是下面这样的,我们简单介绍下它们的作用。
test-vue3
├─.vscode # vscode配置文件
| └─extensions.json # 项目推荐插件列表(可把项目中用到的vscode插件ID写进去,跑项目时没有安装这些插件会推荐安装)
├─public/ # 公共资源目录
├─src/ # 核心开发目录
| ├─App.vue # 项目根组件
| ├─main.js # 项目入口文件
| ├─views/ # 项目视图目录
| | └─dashboard/analysis/index.vue
| ├─stores/ # 统一状态管理目录-pinia
| ├─router/ # 项目路由目录
| | └─index.js
| ├─components/ # 项目公共组件目录
| ├─assets/ # 项目静态资源目录
├─.eslintrc.cjs # eslint 配置文件
├─.gitignore # git忽略文件
├─.prettierrc.json # prettier 配置文件
├─README.md # 项目说明文件
├─index.html # html入口文件
├─package.json # 项目配置和包管理文件
├─vite.config.js # vite 配置文件
2. 格式化配置
注意:
配置完如果还是报错,请关闭重启 vscode
项目初始化的时候安装了 ESLint 和 Prettier,默认配置会给那些自动引入的 API 报红(报错 ref 之类的未定义之类的)
- 根目录下的
.eslintrc.cjs是ESLint配置,当前默认如下
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
extends: [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-prettier'
],
parserOptions: {
ecmaVersion: 'latest'
}
}
- 根目录下的
.prettierrc.json是Prettier配置,当前默认如下
{}
2.1 Eslint 配置
2.11) 自动引入 API/组件 报错配置
报红检测是 ESLint 干的。自动引入配置的导出文件,所有自动引入的 API 都生成了记录在这个文件,只需要将它写入 ESLint 配置的 extends 中让 Lint 工具识别下就好了,如下
注意:
extends这个继承配置的是一个数组,最终会将所有规则项进行合并,出现冲突的时候,后面的会覆盖前面的,我们在初始化项目安装时默认给加上去了 3 个,这三个是什么?
- plugin:vue/vue3-essential
ESLint Vue3插件扩展- eslint:recommended
ESLint官方扩展- @vue/eslint-config-prettier
Prettier NPM扩展
在 根目录/.eslintrc.cjs
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
extends: [
// 新增
'./.eslintrc-auto-import.json',
// 新增结束
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-prettier'
],
parserOptions: {
ecmaVersion: 'latest'
}
}
2.12) 全局参数 API 识别
比如 defineProps、defineEmits、defineExpose,如果你使用 TS,还会用到 withDefaults
ESLint 默认是识别不了这些全局 API 的,此时需要向 ESlint 规则中添加需要辨认的全局变量
ESLint 配置中的 globals 属性就是让项目在 lint 执行期间访问额外的全局变量,简单说就是开发者自定义的全局变量,我们依次加上这些属性就可以了。
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
extends: [
'./.eslintrc-auto-import.json',
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-prettier'
],
// 新增
globals: {
defineEmits: 'readonly',
defineProps: 'readonly',
defineExpose: 'readonly',
withDefaults: 'readonly'
},
// 新增结束
parserOptions: {
ecmaVersion: 'latest'
},
// 新增开始
rules: {
semi: ['warn', 'never'], // 禁止尾部使用分号
'no-debugger': 'warn' // 禁止出现 debugger
}
// 新增结束
}
如上,添加全局属性时,readonly 代表只读,writable 代表可写,可写就是可以手动覆盖这个全局变量的意思。所以不允许覆盖,全部都设置成了 readonly。
这里新增了一个 rules 属性,如单词字面意思,就是规则的配置,可以配置启用一些规则及其各自的错误级别,那由于每个人的喜好不同,只配置了 2 个。
rules 的规则配置有三种:
off 或 0关闭对该规则的校验warn 或 1启用规则,不满足时抛出警告,不会退出编译进程error 或 2启用规则,不满足时抛出错误,会退出编译进程
注意,如果某项规则,有额外的选项,可以通过数组进行传递,数组的第一位必须是错误级别,就比如我们配置的 semi 规则中的 never 就是额外配置项。
2.2 Prettier
{
"semi": false,
"singleQuote": true,
"printWidth": 80,
"trailingComma": "none",
"arrowParens": "avoid",
"tabWidth": 2
}
- semi 代码结尾是否加分号
- singleQuote 是否使用单引号
- printWidth 超过多少字符强制换行
- trailingComma 代码末尾不需要逗号
- arrowParens 单个参数的箭头函数不加括号 x => x
- tabWidth 使用 n 个空格缩进
Prettier 配置比较简单,按照文档和喜好在 .prettierrc.json 文件中配置即可,注意配置的时候一定要和 ESLint 的 rules 比较一下,这里是会发生冲突的地方,检测和格式化规则一定要一致。
2.3 VsCode 扩展
为了开发人员保持同一个环境,保证代码风格一模一样,避免差异性
- 推荐扩展安装
- 常用配置同步
根目录的 .vscode/extensions.json 文件如下:
{
"recommendations": [
"vue.volar",
]
}
3. 架构配置
3.1 公共样式管理、初始化样式
3.11 安装 sass
示例安装版本:1.57.0
npm install sass -D
3.12 公共样式处理
根据下面创建文件,存放公共样式
├─ styles/ # 样式
| ├─ element-plus # 重置element样式
| ├─ └─ el-xxx.scss
| ├─ variables.scss # 变量
| ├─ transition.scss # 动效
| ├─ mixin.scss # mixin
| ├─ normalize.scss # html元素样式重置
| ├─ reset.scss # normalize不支持的样式重置
| ├─ sidebar.scss # 侧边栏
| ├─ index.scss # 样式统一导出接口
- 样式重置
HTML 标签是有默认样式的,一般在写项目时都会直接清除掉这个默认样式,也就是做个重置。
那相较于 Eric Merer 原版的清除样式文件,Normalize.css 它在默认的 HTML 元素样式上提供了跨浏览器的高度一致性,是一种现代的、为 HTML5 准备的优质替代方案,所以我们直接使用它就好了。
下载 Normalize.css 到 styles 文件夹下,当然你也可以直接 npm 安装它,不过我比较喜欢直接下载下来这个文件。
- normalize 不支持的样式重置
也需要一份Normalize.css不支持的一部分样式重置,放到style/reset.scss
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
html,
body {
width: 100%;
height: 100%;
overflow: hidden;
}
#app {
height: 100%;
font-size: 14px;
}
- index.scss 中统一引入
// 重置
@import './normalize.scss';
@import './reset.scss';
@import './variables.scss';
@import './transition.scss';
@import './mixin.scss';
@import './sidebar.scss';
- main.js 引入
import '@/styles/index.scss'
3.2 Utils、Hooks、API 管理
├─ src/
| ├─ api # 公共请求相关
| ├─ utils # 公共方法文件
| ├─ hooks # 公共hooks
4. Vite 内部配置
4.1 自动引入(组件 和 API)
使用 vue过程中,每个 script 或者 js 都会引入(很麻烦)
- 一些像
ref、reactive等 VueAPI VueRouter、Pinia等都要引入一些 API- 自己写的组件也都需要我们手动去引入使用
4.11) 安装插件
示例安装版本:
unplugin-auto-import: 0.12.1
unplugin-vue-components: 0.22.12
npm install -D unplugin-vue-components unplugin-auto-import
4.12) 在 vite.config.js 文件中新增以下内容
// vite.config.ts 新增以下内容
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ArcoResolver } from 'unplugin-vue-components/resolvers'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
AutoImport({
// 需要去解析的文件
include: [
/\.[tj]sx?$/, // .ts, .tsx, .js, .jsx
/\.vue$/,
/\.vue\?vue/, // .vue
/\.md$/ // .md
],
// imports 指定自动引入的包位置(名)
imports: ['vue', 'pinia', 'vue-router'],
// 生成相应的自动导入json文件。
eslintrc: {
// 启用
enabled: true,
// 生成自动导入json文件位置
filepath: './.eslintrc-auto-import.json',
// 全局属性值
globalsPropValue: true
},
resolvers: [ArcoResolver()]
}),
Components({
// imports 指定组件所在目录,默认为 src/components
dirs: ['src/components/', 'src/views/'],
// 需要去解析的文件
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
resolvers: [
ArcoResolver({
sideEffect: true
})
]
})
]
})
解释:
如上,在 API 自动引入插件 AutoImport 中我们写了指定要去解析的文件 include 配置,然后在 import 选项中指定了自动引入的包名,并且所有自动引入的 API 在被自动引入时会添加记录到根目录的 ./.eslintrc-auto-import.json 文件中,方便我们查看都自动引入了哪些东西,后面我们使用这几个包的 API ,就不需要手动引入了,插件会帮我们在文件解析时自动引入。
同样的,在组件自动引入插件 Components 中,我们配置了指定要去解析的文件 include 配置,然后在 import 选项中指定了自动引入的组件目录,以后只要是在这几个目录下写的组件,在使用时都不必须要手动去引入了
例子:
我们在 src/components 文件夹下新建一个 HelloWorld.vue 文件,写上下面内容。
<script setup>
const name = ref('宝贝')
</script>
<template>
<div>hello {{ name }}, this is 子组件 components</div>
</template>
然后,直接在 src/views/dashboard/analysis/index.vue 文件中使用 HelloWorld 组件,不要引入,如下:
<script setup>
const handleClickSmall = () => {
alert('hello, click mini ElButton!')
}
</script>
<template>
<el-space>
<el-button type="primary" size="small" @click="handleClickSmall"
>Small</el-button
>
<el-button type="primary">Medium</el-button>
<el-button type="primary" size="large">Large</el-button>
</el-space>
<!-- 子组件,不需要import组件 -->
<HelloWorld />
</template>
上面创建的 HelloWorld 组件中使用了 Vue 的 ref API,并没有引入它,而后在 HomeView 页面中使用该组件也没有引入,后面使用 Vue、VueRouter、Pinia, 包括自建组件等等都不需要手动引入了,当然,后续你的项目中有用到其他地方你依然可以在插件中去配置!
4.2 环境变量配置
4.21) 新建以下目录
├─ .env # 所有模式都会加载
├─ .env.development # 只在开发模式下加载
├─ .env.production # 只在生产模式下加载
4.22) 设置内容
注意:
在 Vite 中配置的环境变量默认只有以VITE_开头的配置,才会暴露给客户端,才能在项目中获取到。
- .env 文件在所有模式下都会加载,所以这里可以写一些所有环境都通用的环境变量,如下:
# 端口
VITE_PORT = 3100
# 项目标题
VITE_TITLE = QDesign Admin
# 项目简称
VITE_SHORT_NAME = qdesign_admin
- .env.development 开发模式配置
# 环境标识
VITE_ENV = development
# 是否开启 mock
VITE_USE_MOCK = true
# 公共基础路径
VITE_BASE = /
# 代理URL路径
VITE_BASE_URL = /api
# 跨域代理,可以配置多个
# 注意:不能存在空格!!!
# VITE_PROXY = [["/basic-api","http://localhost:3000"],["/upload","http://localhost:3300/upload"]]
# VITE_PROXY= [["/api","https://vvbin.cn/test"]]
- .env.production 生产模式配置
生产环境除了环境标识 VITE_ENV 和开发模式标识不同,其他配置项应尽量保持一致,只是配置项的内容不同而已,不一一的展示了。
# 环境标识
VITE_ENV = production
# 是否开启 mock
VITE_USE_MOCK = true
# 公共基础路径
VITE_BASE = /
# 代理URL路径
VITE_BASE_URL = /basic-api
4.24) 配置 package.json 启动模式
{
"scripts": {
"dev": "vite --mode development",
"build": "vite build --mode production",
"preview": "vite preview --port 8081"
}
}
- 在 dev 脚本命令配置中,传入 mode,其实这个 mode 就是对应的环境文件 .env.[mode]
- 开发环境默认 mode 就是 development,生产环境默认 mode 就是 development
- 所以脚本命令这里不传 mode 也可以
- 如果把开发环境文件由 .env.development 改成 .env.dev,那脚本中 mode 就得传 —-mode dev,build 时也是一样的道理。
- 如果有其他环境,那脚本命令传入对应的 mode 就可以了。
如果想要在 vite.config.js 文件中获取对应运行 mode 环境变量的配置,可以使用 vite 的 loadEnv API。
Vite 的 defineConfig 方法可以接收一个返回配置对象的回调函数,回调函数的参数里可以拿到运行脚本命令时传入的 mode 值,从而使用 loadEnv 方法去在 Vite 配置文件中获取对应 mode 下的环境变量,如下:
// export default defineConfig({}) 修改
export default defineConfig(({ mode }) => {
return {}
})
那其他一些基础配置就不一一说明了,查看 Vite 官方文档
4.25 使用
const service = axios.create({
baseURL: import.meta.env.VITE_BASE_URL
})
5. 第三方插件安装
5.1 Sass
示例安装版本:1.57.0
npm install sass -D
5.2 Element Plus
5.21) 安装
使用包管理器
示例安装版本: 2.2.27
# npm
npm install element-plus --save
# Yarn
$ yarn add element-plus
# pnpm
$ pnpm install element-plus
5.22) 使用
// main.js
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
安装插件
示例安装版本:
unplugin-auto-import: 0.12.1
unplugin-vue-components: 0.22.12
npm install -D unplugin-vue-components unplugin-auto-import
vite.config.js 新增以下内容
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: [
// ...
AutoImport({
resolvers: [ElementPlusResolver()]
}),
Components({
resolvers: [ElementPlusResolver()]
})
]
})
5.3 VueUse
VueUse 没用过的话可以先把它理解为一个基于 Vue 的工具库,Vue2、Vue3 都可以用,有很多实用的方法、组件包括指令,超级方便,后续我们会用到其中的一些方法,所以先装上
5.31) 安装
# npm
npm i @vueuse/core
# pnpm
pnpm add @vueuse/core
5.32) 配置自动引入
VueUse 不止有方法,还有组件和指令,所以我们还是需要上面两个自动引入的插件去处理,那由于作者是一个人,解析器都内置在自动引入插件中了,所以我们直接导出用就可以了。
我们配置 VueUse 的组件和指令自动引入需要两个解析器,还是在 vite.config.js 配置文件中引入,如下:
// ArcoVue、VueUse 组件和指令的自动引入解析器
import {
ArcoResolver,
VueUseComponentsResolver,
VueUseDirectiveResolver
} from 'unplugin-vue-components/resolvers'
使用的话,只需要在配置文件 plugins 模块中之前写过的 Components 插件中使用一下这两个解析器就好了:
plugins: [
Components({
// ...
VueUseComponentsResolver(),
VueUseDirectiveResolver()
})
]
那 API 方法的自动引入就很简单了,还是配置文件中只需要在之前用过的 AutoImport 插件中添加一个 VueUse 包名配置就行了:
plugins: [
AutoImport({
// 新增 '@vueuse/core'
imports: ['vue', 'pinia', 'vue-router', '@vueuse/core'],
resolvers: [ArcoResolver()]
})
]
这样我们就可以在项目中随时随地的使用 VueUse 了!建议大家有时间可以去看看 VueUse 的源码实现,也并不复杂,它有很多最佳实践,可以给我们使用 Vue3 提供很大的帮助!
5.4 Mock
项目开发阶段通常会使用 mock 数据。插件 vite-plugin-mock 同时提供了开发环境和生产环境下的数据 mock 服务,简单好用。
5.41) 安装
插件依赖于 mockjs,需要一并安装:
示例安装版本:
mockjs: 1.1.0
vite-plugin-mock: 2.9.6
npm add -D vite-plugin-mock mockjs
5.42) 配置
根据情况任选一种即可
- 根据 env 配置是否开启 mock
- 根据环境(开发环境/生产环境)配置是否开启 mock
5.421 根据 env 文件配置是否开启 mock
在 vite.config.js 配置文件启用插件。
import { defineConfig, loadEnv } from 'vite'
import { viteMockServe } from 'vite-plugin-mock'
// https://vitejs.dev/config/
export default defineConfig(mode => {
return {
plugins: [
viteMockServe({
// 只在开发阶段开启 mock 服务
localEnabled: loadEnv(mode, process.cwd()).VITE_USE_MOCK
})
]
}
})
解决 eslint 报错: 'process' is not defined.
在 eslintrc.cjs
module.exports = {
globals: {
process: true
}
}
5.422 根据开发环境和生产环境 配置是否开启 mock
在 vite.config.js 配置文件启用插件。
Mock 服务通常只用于开发阶段,因此我们需要在配置文件中判断当前所处环境。
在 webpack 中通常会配置一个 NODE_ENV 的环境变量。而在 Vite 中,不用开发者进行设置,它提供了一种方便的判断开发环境和生产环境的方式,如下:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { viteMockServe } from 'vite-plugin-mock'
export default defineConfig((config) => {
const { command } = config
return {
plugins: [
vue(),
viteMockServe({
// 只在开发阶段开启 mock 服务
localEnabled: command === 'serve'
})
]
}
})
上面,配置文件导出一个立即执行的 defineConfig 函数。它又接收一个函数作为参数,该函数接收一个 config 参数,它包含一个 command 属性。当在命令行中执行 vite (开发)命令时, command 的值为 serve,当执行 vite build (构建)命令时,对应的值为 build。据此,可以识别所处环境。
插件 vite-plugin-mock 有一个配置项 localEnabled,可以决定是否开启 mock 服务。默认即为开启状态。结合 command 属性,就可以动态的切换 mock 服务的状态了。
5.43) 编写 mock server
该插件开箱即用。默认它会读取项目根目录下 mock 文件下的内容,作为 mock server。
在根目录新建一个模拟用户接口的服务,它导出一个数组,数组里每一项用来模拟一个接口:
// /mock/user.js
export default [
// 用户登录
{
// 请求地址
url: "/api/user/login",
// 请求方法
method: "post",
// 响应数据
response: () => {
return {
code: 0,
message: 'success',
data: {
token: "Token",
username: "昆吾kw"
}
}
}
}
]
插件内部使用了 Connect 来提供接口服务,它是一个比 Express 更悠久的 Node HTTP 框架。上面的写法就相当于创建了一个这样的接口服务:
app.post('/api/user/login', (req, res) => {
res.send({
code: 0,
message: 'success',
data: {
token: 'Token',
username: '昆吾kw'
}
})
})
由于开启了 mock 服务,当前端在发出 ajax 请求时,会被拦截到,交由 mock 服务处理。没有做数据校验,前端传任何数据来都返回上面的结果。
const result = await axios.post('/api/user/login', userData)
6. 参考文献
如有侵权,可联系本人删除。