网上的后台管理系统模版一大堆,删起来麻烦,
xjy_admin是我自己搭建的通用后台管理模板,并不断完善中......
🔥 前言
经过一段时间的打磨(具体忘了),迎来管理系统的第一个版本, 相较于其他后台管理模板,本后台管理模版只包含基本的刷新,全屏以及暗黑模式效果。本模板只供学习使用,难免会存在一些bug,还请见谅。
😀 项目介绍
一个基于Vue3.4+Element-plus+Vite搭建的轻量级后台管理模板,本项目分一个登录接口和一个用户信息接口,并且采用mockjs模拟数据,有简单的权限划分。
✨ 效果展示
在线预览
仓库地址Gitee
首页
🏅 技术栈
| 技术栈 | 描述 | 官网 |
|---|---|---|
| Vue3 | 渐进式JavaScript框架 | cn.vuejs.org/ |
| Element-plus | 基于 Vue 3,面向设计师和开发者的组件库 | element-plus.org/zh-CN/ |
| Vite | 前端构建工具 | vitejs.cn/vite3-cn/ |
| Pinia | 符合直觉的 Vue.js 状态管理库 | pinia.web3doc.top/ |
| tinymce | 功能强大、所见即所得的富文本编辑器 | tinymce.ax-z.cn/ |
| Echarts | 一个基于 JavaScript 的开源可视化图表库 | echarts.apache.org/zh/index.ht… |
| VueUse | 基于Vue组合式API的实用工具集 | www.vueusejs.com/ |
| animate.css | 一个现成的跨浏览器动画库 | animate.style/ |
🌈 项目基本配置
项目全局配置
代码统一规范
- Eslint:语法规则和代码风格检查
- Prettier:美化代码样式
- Stylelint: CSS 统一规范和代码检测
.eslintrc.cjs
js复制代码// @see https://eslint.bootcss.com/docs/rules/ module.exports = { env: { browser: true, es2021: true, node: true, jest: true, }, /* 指定如何解析语法 */ parser: ''vue-eslint-parser'', /** 优先级低于 parse 的语法解析配置 */ parserOptions: { ecmaVersion: ''latest'', sourceType: ''module'', parser: ''@typescript-eslint/parser'', jsxPragma: ''React'', ecmaFeatures: { jsx: true, }, }, /* 继承已有的规则 */ extends: [ ''eslint:recommended'', ''plugin:vue/vue3-essential'', ''plugin:@typescript-eslint/recommended'', ''plugin:prettier/recommended'', ], plugins: [''vue'', ''@typescript-eslint''], /* * "off" 或 0 ==> 关闭规则 * "warn" 或 1 ==> 打开的规则作为警告(不影响代码执行) * "error" 或 2 ==> 规则作为一个错误(代码不能执行,界面报错) */ rules: { // eslint(https://eslint.bootcss.com/docs/rules/) ''no-var'': ''error'', // 要求使用 let 或 const 而不是 var ''no-multiple-empty-lines'': [''warn'', { max: 1 }], // 不允许多个空行 ''no-console'': process.env.NODE_ENV === ''production'' ? ''error'' : ''off'', ''no-debugger'': process.env.NODE_ENV === ''production'' ? ''error'' : ''off'', ''no-unexpected-multiline'': ''error'', // 禁止空余的多行 ''no-useless-escape'': ''off'', // 禁止不必要的转义字符 // typeScript (https://typescript-eslint.io/rules) ''@typescript-eslint/no-unused-vars'': ''off'', // 禁止定义未使用的变量 ''@typescript-eslint/prefer-ts-expect-error'': ''off'', // 禁止使用 @ts-ignore ''@typescript-eslint/no-explicit-any'': ''off'', // 禁止使用 any 类型 ''@typescript-eslint/no-non-null-assertion'': ''off'', ''@typescript-eslint/no-namespace'': ''off'', // 禁止使用自定义 TypeScript 模块和命名空间。 ''@typescript-eslint/semi'': ''off'', // eslint-plugin-vue (https://eslint.vuejs.org/rules/) ''vue/multi-word-component-names'': ''off'', // 要求组件名称始终为 “-” 链接的单词 ''vue/script-setup-uses-vars'': ''error'', // 防止<script setup>使用的变量<template>被标记为未使用 ''vue/no-mutating-props'': ''off'', // 不允许组件 prop的改变 ''vue/attribute-hyphenation'': ''off'', // 对模板中的自定义组件强制执行属性命名样式 }, }
.prettierrc.json
js复制代码{ "singleQuote": false, "semi": false, "bracketSpacing": true, "htmlWhitespaceSensitivity": "ignore", "endOfLine": "auto", "trailingComma": "all", "tabWidth": 2 }
.stylelintrc.cjs
js复制代码// @see https://stylelint.bootcss.com/ // 美化css书写的样式 module.exports = { extends: [ ''stylelint-config-standard'', // 配置stylelint拓展插件 ''stylelint-config-html/vue'', // 配置 vue 中 template 样式格式化 ''stylelint-config-standard-scss'', // 配置stylelint scss插件 ''stylelint-config-recommended-vue/scss'', // 配置 vue 中 scss 样式格式化 ''stylelint-config-recess-order'', // 配置stylelint css属性书写顺序插件, ''stylelint-config-prettier'', // 配置stylelint和prettier兼容 ], overrides: [ { files: [''**/*.(scss|css|vue|html)''], customSyntax: ''postcss-scss'', }, { files: [''**/*.(html|vue)''], customSyntax: ''postcss-html'', }, ], ignoreFiles: [ ''**/*.js'', ''**/*.jsx'', ''**/*.tsx'', ''**/*.ts'', ''**/*.json'', ''**/*.md'', ''**/*.yaml'', ], /** * null => 关闭该规则 * always => 必须 */ rules: { ''value-keyword-case'': null, // 在 css 中使用 v-bind,不报错 ''no-descending-specificity'': null, // 禁止在具有较高优先级的选择器后出现被其覆盖的较低优先级的选择器 ''function-url-quotes'': ''always'', // 要求或禁止 URL 的引号 "always(必须加上引号)"|"never(没有引号)" ''no-empty-source'': null, // 关闭禁止空源码 ''selector-class-pattern'': null, // 关闭强制选择器类名的格式 ''property-no-unknown'': null, // 禁止未知的属性(true 为不允许) ''block-opening-brace-space-before'': ''always'', //大括号之前必须有一个空格或不能有空白符 ''value-no-vendor-prefix'': null, // 关闭 属性值前缀 --webkit-box ''property-no-vendor-prefix'': null, // 关闭 属性前缀 -webkit-mask ''selector-pseudo-class-no-unknown'': [ // 不允许未知的选择器 true, { ignorePseudoClasses: [''global'', ''v-deep'', ''deep''], // 忽略属性,修改element默认样式的时候能使用到 }, ], }, }
🎈 按钮主题色
在style/element/index.scss中配置
js复制代码/* 只需要重写你需要的即可 */ @forward ''element-plus/theme-chalk/src/common/var.scss'' with ($colors: ( ''primary'': (// 主色 ''base'':#0F5197, ), ''success'': ( // 成功色 ''base'': #199D33, ), ''info'': (''base'': #4e4f51, ), ''warning'': ( // 警告色 ''base'': #e26f03, ), ''danger'': ( // 危险色 ''base'': #de2e06, ), ''error'': ( // 危险色 ''base'': #de2e06, ), ));
vite.config.ts 配置
js复制代码css: { preprocessorOptions: { scss: { javascriptEnabled: true, // 自动导入定制化样式文件进行样式覆盖 additionalData: ` @use "@/styles/element/index.scss" as *; @use "@/config/public.scss" as *; `, }, }, },
🔑 项目集成
mock.js
mock.js 生成随机数据,拦截 Ajax 请求
参考:mock.js 官网
安装
js复制代码pnpm install -D vite-plugin-mock mockjs
vite.config.ts 配置
js复制代码import { viteMockServe } from ''vite-plugin-mock'' plugins: [ viteMockServe({ mockPath: "./src/mock", // localEnabled: true, }) ]
UnoCSS
UnoCSS 是即时原子 CSS 引擎,通俗易懂的讲,就是在
template模版中书写css
参考:UnoCSS中文文档
安装
js复制代码pnpm install -D unocss
vite.config.ts 配置
js复制代码复制代码 // vite.config.ts import UnoCSS from ''unocss/vite'' export default { plugins: [ UnoCSS({ /* options */ }), ], }
main.js中
js复制代码// main.js import "virtual:uno.css"
uno.config.js中可自行配置
js复制代码// uno.config.ts import { defineConfig, presetAttributify, presetIcons, presetTypography, presetUno, presetWebFonts, transformerDirectives, transformerVariantGroup, } from "unocss" export default defineConfig({ shortcuts: { "flex-center": "flex justify-center items-center", "flex-x-center": "flex justify-center", "flex-y-center": "flex items-center", "wh-full": "w-full h-full", "flex-x-between": "flex items-center justify-between", "flex-x-end": "flex items-center justify-end", "absolute-lt": "absolute left-0 top-0", "absolute-rt": "absolute right-0 top-0 ", "fixed-lt": "fixed left-0 top-0", "b1-red": "b-1 border-solid b-red", }, theme: { colors: { primary: "var(--el-color-primary)", primary_dark: "var(--el-color-primary-light-5)", }, }, presets: [ presetUno(), presetAttributify(), presetIcons(), presetTypography(), presetWebFonts({ fonts: { // ... }, }), ], transformers: [transformerDirectives(), transformerVariantGroup()], })
VsCode安装提示插件
插件效果预览
🏆 功能封装
Svg使用
js复制代码// <template>中 <SvgIcon icon="" width="15px" height="15px" color="#fff" />
js复制代码//vite中自行调整svg图标的储存位置 createSvgIconsPlugin({ iconDirs: [path.resolve(process.cwd(), "src/assets/svgs")], symbolId: "icon-[dir]-[name]", }),
svg图标存放位置为 assets/svgs
WangEditor编辑器集成
js复制代码// 父组件中 <template> <WangEditor v-model="editVal" height="calc(100vh - 180px)" /> </template> <script setup lang="ts"> import { ref, watchEffect } from "vue" //初始值 const editVal = ref("Hello! WangEditor") watchEffect(() => { console.log(editVal.value) }) </script>
js复制代码<template> <div class="wang_edit" :class="{ dark: useSetting.dark }"> <Toolbar id="toolbar-container" :editor="editorRef" :defaultConfig="toolbarConfig" mode="default" /> <Editor id="editor-container" v-model="valueHtml" :defaultConfig="editorConfig" mode="default" @onCreated="handleCreated" /> </div> </template> <script setup lang="ts"> import { useSettingStore } from "@/stores/modules/setting" import "@wangeditor/editor/dist/css/style.css" // 引入 css import { onBeforeUnmount, ref, shallowRef, onMounted } from "vue" import { Editor, Toolbar } from "@wangeditor/editor-for-vue" const useSetting = useSettingStore() const props = withDefaults( defineProps<{ height: string }>(), { height: "560px", }, ) const valueHtml = defineModel() // 编辑器实例,必须用 shallowRef const editorRef = shallowRef() const toolbarConfig = {} const editorConfig = { placeholder: "请输入内容...", MENU_CONF: { uploadImage: { // 自定义图片上传 async customUpload(file: any, insertFn: any) { console.log(file, insertFn) // 调用后端接口,上传图片 // 拿到上传路劲插入编辑器 // insertFn(url) }, }, }, } // 组件销毁时,也及时销毁编辑器 onBeforeUnmount(() => { const editor = editorRef.value if (editor == null) return editor.destroy() }) const handleCreated = (editor: any) => { editorRef.value = editor // 记录 editor 实例,重要! } </script> <style scoped lang="scss"> .wang_edit { border: 1px var(--el-border-color-dark) solid; border-radius: 5px; &.dark { --w-e-textarea-bg-color: #333; --w-e-toolbar-bg-color: #333; --w-e-toolbar-color: gray; --w-e-textarea-color: #fff; } #toolbar-container { border-bottom: 1px solid var(--el-border-color-dark); border-top-right-radius: 5px; border-top-left-radius: 5px; } #editor-container { height: v-bind("props.height") !important; overflow: hidden; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; } } </style>
👻 项目运行
项目启动
js复制代码# 安装 pnpm npm install pnpm -g # 安装依赖 pnpm install # 项目运行 pnpm run dev
项目语法检查
js复制代码#语法检查 pnpm run lint #语法修复 pnpm run fix #css美化 pnpm run format
项目打包
js复制代码pnpm run build
✍️ 写在最后
本篇从项目规范,项目运行,项目打包,详细讲述基于Vue3.4+Element-plus技术栈0到1搭建简洁,易懂的前端后台管理框架。如有问题欢迎指出。