vue系列(三)——手把手教你搭建一个vue3管理后台基础模板
目录
一、前言:
二、网站页面分析
三、开发步骤
(一)、安装element
(二)、安装使用svg插件
(三)、编写主界面框架代码
(四)、编写菜单栏
(五)、新建页面及路由
(六)、定制页面标签栏
第一步:
第二步:
(七)、修改封装菜单栏
(八)、添加面包屑
四、结尾
一、前言:
先上图,项目模板成品截图:
开源的vue管理后台模板很多,如需快速开发一个后台管理可搜索“vue管理后台模板”查找,本文旨在熟悉vue开发过程实践,适合vue刚入门的小伙伴阅读和动手实践,内容偏长,只想要代码的同学可直接点击 源代码。通过本章博客你可以学到:
(1)、element UI组件库的使用。
(2)、如何自定义组件。
(3)、路由的熟练使用。
(4)、vue项目开发思想的提升。
(5)、……
本项目在上一章节集成项目基础上开发,可先点击下方链接阅读。(如阅读本章无障碍请忽略)
vue系列(二)——vue3基础项目(集成框架)搭建_萧萧风的博客-CSDN博客目录一、新建项目二、集成路由三、安装配置axios(网络请求库)四、使用vuex(暂无)五、结尾打开编辑器新建项目,填写项目名称,点击创建,之后等待项目加载完成就可以了。我的Hbuilder X 版本是3.4.14新建的项目目录下面是vue项目加载页面的形式,单页渲染,所有的内容展示都是在index.html页面上进行渲染,而App.vue是index.html里面最外层的组件容器、包含全局的js代码css样式。所有的页面的渲染是在App.vue容器里面进行文件main.js:入口js文件,所有全局文件的引https://blog.csdn.net/xxfen_/article/details/125327388?spm=1001.2014.3001.5501
二、网站页面分析
网站由登录页、主界面、内容页组成。
主界面整体模块是由:
(1)、导航栏;
(2)、左测导航菜单栏;
(3)、页面标签卡栏;
(4)、内容栏(展示页面)。
组成。
菜单栏的点击切换改变的只是内容栏的内容,由此得出:
登录页和主界面是一级路由,内容页是主界面下的嵌套路由。
三、开发步骤
(一)、安装element
官网: 一个 Vue 3 UI 框架 | Element Plus。
首先安装国内npm镜像,这样下载资源包速度会更快
npm install cnpm -g --registry=https://registry.npmmirror.com
然后,安装element
npm install element-plus --save
引入项目,在main.js文件中加入以下代码
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
app.use(ElementPlus)
测试一下引入是否成功,在home.vue中加入按钮组件
<el-button type="primary">Primary</el-button>
运行项目:npm run dev
运行效果如下,说明引入成功:
(二)、安装使用svg插件
- 安装:
npm i vite-plugin-svg-icons -D
- 在src下新建存放svg目录:
- 在components目录下新建组件:SvgIcon.vue
<template><svg aria-hidden="true"><use :xlink:href="symbolId" /></svg>
</template><script>import { defineComponent, computed } from 'vue';export default defineComponent({name: 'SvgIcon',props: {prefix: {type: String,default: 'icon',},name: {type: String,required: true,},},setup(props) {const symbolId = computed(() => `#${props.prefix}-${props.name}`);return { symbolId };},});
</script>
- 在vite.config.js中配置:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(),createSvgIconsPlugin({// 指定需要缓存的图标文件夹iconDirs: [path.resolve(process.cwd(), 'src/icons/svg')],// 指定symbolId格式symbolId: '[name]',})]
})
- 在main.js中引入,添加代码:
//导入Svg图片插件,可以在页面上显示Svg图片
import 'virtual:svg-icons-register'
import SvgIcon from "./components/SvgIcon.vue";
app.component('SvgIcon',SvgIcon)
- 到了这里,运行项目出现报错:没有找到fast-glob。就需要安装fast-glob。
npm i fast-glob
- 测试使用
打开Icon 图标 | Element Plus
点击图标复制svg内容
在新建的svg目录下新建svg文件,名称格式:icon-“图标名称”,粘贴内容保存
在页面中使用:
<SvgIcon name="aim" class="icon-svg" />
(三)、编写主界面框架代码
- 先搭建一个整体框架,home.vue 代码
<template v-slot:default><div :class="['content',isCollapse?'menu--fold':'menu--unfold']"><!-- 侧边菜单栏 --><div class="menuLeft"><div class="menu-nav-header"><span>{{isCollapse?'控制台':'管理控制台'}}</span></div><!--todo 菜单栏组件 --></div><!-- 右边内容 --><div class="content-main"><div class="navTop horizontalView"><div class="nav_tools horizontalView"><SvgIcon :name="isCollapse?'expand':'fold'" class="icon-svg" @click="isCollapse=!isCollapse" /></div></div><!-- todo 内容组件 --></div></div>
</template><script>
export default {components: {},data: function() {return {isCollapse: false}}
}
</script><style>@import url('../assets/css/home.css');
</style>
- 编写css样式
通用的放在base.css中,页面独有的放在home.css
- base.css代码:
.content {width: 100%;height: 100%;font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
}/* 水平布局 居中*/
.horizontalView {position: relative;flex-direction: row;display: flex;align-items: center;
}/* 垂直布局居中 */
.verticalView {position: relative;flex-direction: column;display: flex;align-items: center;
}/* 居中 */
.center {position: absolute;top: 50%;left: 50%;font-size: 28px;transform: translate(-50%, -50%);
}.w100 {width: 100%;
}.h100 {height: 100%;
}
.icon-svg {width: 1.4rem;height: 1.4rem;fill: currentColor;overflow: hidden;
}
- home.css代码:
/* -------侧边栏 折叠 */
.menu--fold .menuLeft {width: 64px;
}.menu--fold .content-main {margin-left: 64px;
}/* --------------------- *//* ---------侧边栏 展开 */
.menu--unfold .menuLeft {width: 230px;
}.menu--unfold .content-main {margin-left: 230px;
}/* ------------- */.navTop {position: relative;width: 100%;height: 50px;z-index: 100;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);box-sizing: border-box;background: white;
}.nav_tools {height: 100%;
}.nav_tools .icon-svg {margin-left: 10px;color: #5b5b5b;
}.menuLeft {position: fixed;top: 0;left: 0;bottom: 0;z-index: 1020;overflow: hidden;background-color: #263238;
}.content-main {position: relative;background: #f1f4f5;height: 100%;}
.menu-nav-header {color: white;height: 50px;line-height: 50px;text-align: center;font-size: 20px;font-weight: bold;/* background-color: #9fbea7; */background-color: #566f7e;
}/* 动画 */
.nav_tools,
.menuLeft,
.content-main {transition: inline-block 0.3s, left 0.3s, width 0.3s, margin-left 0.3s, font-size 0.3s;
}
- base.css放在app.vue
@import url("./assets/css/base.css");
- 看看页面效果:
- 点击上边折叠按钮
(四)、编写菜单栏
请先去了解组件使用文档:Menu 菜单 | Element Plus
复制实例代码自定义内容属性及样式,关闭组件提供的折叠动画,自定义动画样式
- 在home.vue中加入修改菜单组件代码
<!--todo 菜单栏组件 --><el-menu active-text-color="#fff" background-color="#263238" class="el-menu-vertical-demo":collapse-transition="false" default-active="2" text-color="#96a4ab " @open="handleOpen"@close="handleClose" :collapse="isCollapse"><el-menu-item index="1"><SvgIcon name="home" class="icon-svg" /><span slot=""> 首页</span></el-menu-item><el-sub-menu index="2"><template #title><SvgIcon name="img" class="icon-svg" /><span> 图片管理</span></template><el-menu-item index="1-1"><SvgIcon name="img" class="icon-svg" /><span> 图片1</span></el-menu-item><el-menu-item index="1-2"><SvgIcon name="img" class="icon-svg" /><span> 图片2</span></el-menu-item><el-sub-menu index="1-4"><template #title><SvgIcon name="img" class="icon-svg" /><span> 图片3</span></template><el-menu-item index="1-4-1"><SvgIcon name="img" class="icon-svg" /><span> 图片三级子菜单</span></el-menu-item></el-sub-menu></el-sub-menu><el-sub-menu index="3"><template #title><SvgIcon name="collection" class="icon-svg" /><span> 收藏管理</span></template><el-menu-item index="3"><SvgIcon name="collection" class="icon-svg" /><span class="icon-text"> 收藏</span></el-menu-item></el-sub-menu><el-menu-item index="4"><SvgIcon name="about" class="icon-svg" /><span> 设置</span></el-menu-item></el-menu>
- home.css 中加入修改样式代码
/* 修改菜单栏样式样式 */.menuLeft .el-menu {border-right: none;
}.el-menu-vertical-demo:not(.el-menu--collapse) {border-right: none;width: 230px;
}.el-menu .icon-text {margin-left: 10px;
}
- 页面效果:
菜单栏编写到这还没完呢,上面这种写法是每次添加、修改或删除菜单都要在页面中找到位置再修改有点繁琐,在页面代码多了或菜单项好多时去编辑修改更是麻烦的一比,所以等后面再来优化代码,把菜单封装成菜单数据集合,然后再在页面中for循环展示。
(五)、新建页面及路由
- 新建页面:
index.vue,img1.vue,collect.vue,set.vue 。并在页面内加上页面标识文字。
- 配置路由:
router目录下index.js代码:
// import Vue from 'vue' //引入Vue
import {createRouter,createWebHashHistory
} from 'vue-router' //引入vue-router
// Vue.use(Router) //Vue全局使用Routerimport home from '../views/home.vue'
import login from '../views/login.vue'
import index from '../views/index.vue'
import collect from '../views/collect.vue'
import set from '../views/set.vue'
import img1 from '../views/img1.vue'const routes = [{path: '',redirect: "home"}, {path: '/',redirect: "home"},{path: '/login',name: 'login',component: login,meta: {title: '登录'}},{path: '/home',name: 'home',component: home,/* 子路由 */children: [{path: '/',redirect: "index"},{path: '',redirect: "index"}, {path: '/index',name: 'index',component: index,meta: {title: '首页',}},{path: '/collect',name: 'collect',component: collect,meta: {title: '收藏',isTab: true}},{path: '/img1',name: 'img1',component: img1,meta: {title: '图片1',isTab: true}},{path: '/set',name: 'set',component: set,meta: {title: '设置',isTab: true}}]}
];// 导航守卫
// 使用 router.beforeEach 注册一个全局前置守卫,判断用户是否登陆
/* router.beforeEach((to, from, next) => {if (to.path === '/login') {next();} else {let token = localStorage.getItem('Authorization');if (token === null || token === '') {next('/login');} else {next();}}
}); */
const router = createRouter({history: createWebHashHistory(),routes
})
export default router;
- 在home.vue中加入路由组件测试一下路由跳转:
<router-view />
- 在菜单项中加入跳转路由代码
在“首页”菜单项加上点击跳转路由代码:@click="$router.push({ name: 'index' })"
同理,在其它菜单项上加入相应代码。
- 测试效果
点击“设置”
点击“收藏”
ok,路由配置成功!
(六)、定制页面标签栏
二步走:
(1)、监听路由的切换,存储跳转的路由的name(或path)集合,并存储当前的路由name。
(2)、使用 el-tabs标签页组件Tabs 标签页 | Element Plus,自定义样式,编写内容组件。
第一步:
- 监听路由变化,watch与data同层:
watch: {$route: {handler(to, from) {if (to.path != from.path) {// 处理路由this.routeHandle(to);}}}},
- 算了,直接放js全部代码吧:
<script>export default {components: {},data: function() {return {isCollapse: false,mainTabs: [],mainTabsActiveName: '',menuActiveName: '',menus: []}},created() {let that = this;that.routeHandle(that.$route);},// 监听路由变化watch: {$route: {handler(to, from) {if (to.path != from.path) {// 处理路由this.routeHandle(to);}}}},methods: {resetDocumentClientHeight: function() {this.documentClientHeight = document.documentElement['clientHeight'];window.onresize = () => {this.documentClientHeight = document.documentElement['clientHeight'];this.loadSiteContentViewHeight();};},loadSiteContentViewHeight: function() {let height = this.documentClientHeight - 52; //减去导航栏高度50 console.log(this.$route.meta.isTab)if (this.$route.meta.isTab) {height -= 70; //减去tab栏高度40,减去上下边距30/* this.siteContentViewHeight = {'min-height': height + 'px'}; */this.siteContentViewHeight = height;} else {height -= 30;//给内容区设置高度this.siteContentViewHeight = height;}},routeHandle: function(route) {//每次切换页面,重新计算页面高度和内容区高度this.resetDocumentClientHeight();this.loadSiteContentViewHeight();if (route.meta.isTab) {// tab选中, 不存在先添加var tab = this.mainTabs.filter(item => item.name === route.name)[0];if (!tab) {if (route.meta.isDynamic) {route = this.dynamicMenuRoutes.filter(item => item.name === route.name)[0];if (!route) {return console.error('未能找到可用标签页!');}}tab = {menuId: route.meta.menuId || route.name,name: route.name,title: route.meta.title,iframeUrl: route.meta.iframeUrl || '',params: route.params,query: route.query};this.mainTabs = this.mainTabs.concat(tab);}this.menuActiveName = tab.menuId + '';this.mainTabsActiveName = tab.name;}},mounted: function() {let that = this;that.resetDocumentClientHeight();that.loadSiteContentViewHeight();}}}
</script>
第二步:
- 编写组件
<!-- todo 内容组件 --><el-tabs v-if="$route.meta.isTab" v-model="mainTabsActiveName" :closable="true"@tab-click="selectedTabHandle" @tab-remove="removeTabHandle"><el-scrollbar ref="scroll" :height="siteContentViewHeight+32+'px'" @scroll="scroll"><el-tab-pane v-for="item in mainTabs" :label="item.title" :name="item.name"><el-card :style="'min-height:'+siteContentViewHeight + 'px'"><router-view v-if="item.name === mainTabsActiveName" /></el-card></el-tab-pane></el-scrollbar></el-tabs><div v-else><el-scrollbar ref="scroll" :height="siteContentViewHeight+32+'px'" @scroll="scroll"><!-- 主入口标签页 e --><el-card :style="'min-height:'+ siteContentViewHeight + 'px'"><router-view /></el-card></el-scrollbar></div>
- 修改样式:
/* 修改标签栏样式 */
.content-main .el-tabs .el-tabs__header {z-index: 90;padding: 0 55px 0 15px;box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.12), 0 0 6px 0 rgba(0, 0, 0, 0.04);background-color: #fff;
}.content-main .el-tabs .el-tabs__nav-wrap::after {width: 0px;
}.content-main .el-scrollbar .el-card {margin: 15px 15px;}
.content-main .el-tabs .el-tabs__header{margin: unset;
}
.content-main .el-tabs .el-tab-pane{
}
- 效果:
(七)、修改封装菜单栏
- 在router文件下新建文件
- menu.js文件代码:
var mu = {longTitle: '管理控制台',littleTitle: '控制台',items: [{iconName: 'home',name: '首页',routerName: 'index',disabled: false}, {iconName: 'img',name: '图片管理',submenu: [{iconName: 'img',name: '图片一',routerName: 'img1',disabled: false}, {iconName: 'img',name: '图片二',routerName: 'img2',disabled: false}, {iconName: 'img',name: '图片三管理',submenu: [{iconName: 'img',name: '图片三',routerName: 'img1',disabled: true}]}]},{iconName: 'collection',name: '收藏管理',submenu: [{iconName: 'collection',name: '收藏',routerName: 'collect',disabled: false}]},{iconName: 'about',name: '设置',routerName: 'set',disabled: false}]
}
export default mu;
- 重新写菜单组件:
<div class="menu-nav-header"><span>{{isCollapse?littleTitle:longTitle}}</span></div><el-menu active-text-color="#fff" background-color="#263238" class="el-menu-vertical-demo":collapse-transition="false" text-color="#96a4ab " @open="handleOpen"@close="handleClose" :collapse="isCollapse"><template v-for="(item,index) in menus"><el-menu-item v-if="!item.submenu" :index="index" @click="$router.push({ name: item.routerName })" :disabled="item.disabled"><SvgIcon :name="item.iconName" class="icon-svg" /><span slot=""> {{item.name}}</span></el-menu-item><el-sub-menu v-else :index="index"><template #title><SvgIcon :name="item.iconName" class="icon-svg" /><span slot=""> {{item.name}}</span></template><template v-for="(submenuItem,submenuIndex) in item.submenu"><el-menu-item v-if="!submenuItem.submenu" :index="index+'-'+submenuIndex" :disabled="submenuItem.disabled"@click="$router.push({ name: submenuItem.routerName })"><SvgIcon :name="submenuItem.iconName" class="icon-svg" /><span slot=""> {{submenuItem.name}}</span></el-menu-item><el-sub-menu v-else :index="index+'-'+submenuIndex"><template #title><SvgIcon :name="submenuItem.iconName" class="icon-svg" /><span slot=""> {{submenuItem.name}}</span></template><el-menu-item v-for="(item3,index3) in submenuItem.submenu" :index="index" :disabled="item3.disabled"@click="$router.push({ name: item3.routerName })"><SvgIcon :name="item3.iconName" class="icon-svg" /><span slot=""> {{item3.name}}</span></el-menu-item></el-sub-menu></template></el-sub-menu></template></el-menu>
只嵌套了三级子菜单,如果有更多级子菜单,需要在组件中再嵌套多个for循环即可。
- script代码中首先导入menu
import mu from '../router/menu/menu.js';
- 在created中调用
这样,修改菜单栏就只需要在menu.js进行编辑了,不再需要修改页面代码。
(八)、添加面包屑
- 页面中加入面包屑组件:
<el-breadcrumb separator="/"><el-breadcrumb-item v-if="!breadcrumbList.size && breadcrumbList[0]!='首页'" :to="{ name: 'index' }">首页</el-breadcrumb-item><el-breadcrumb-item v-for="it in breadcrumbList">{{it}}</el-breadcrumb-item></el-breadcrumb>
- 在created中,将菜单栏集合做下处理,处理成下面格式:
{
"首页":["首页"],
"图片一":["图片管理","图片一"],
......
}
- 代码:
//菜单项层级处理,做一个面包屑集合保存var mus=that.menusfor (let i1 of mus) {if (i1.submenu) {for (let i2 of i1.submenu) {if (i2.submenu) {for (let i3 of i2.submenu) {if (!i3.submenu) {that.breadcrumbObj[i3.name] = [i1.name, i2.name, i3.name];}}} else {that.breadcrumbObj[i2.name] = [i1.name, i2.name];console.log(i2.name)}}} else {that.breadcrumbObj[i1.name] = [i1.name];console.log(i1.name)}}
路由发生变化时赋值,在watch中加入:
this.breadcrumbList = this.breadcrumbObj[to.meta.title]
注意:路由中的name要与菜单中的name保持一致。
四、结尾
到这里,一个简单的管理后台基础模板就完成了,源代码拿走不谢,码字不易,既然看到了这里,点个赞再走吧。
vue系列(三)——手把手教你搭建一个vue3管理后台基础模板相关推荐
- vue+node.js手把手教你搭建一个直播平台(二)
上一期,帅气的小羽给老铁们介绍了直播平台的项目的后端搭建,这期就让小羽带大家来搭建一下前端的框架. 1.创建前端工程 毫无疑问,搭建一个项目的框架,那第一步肯定是得创建一个工程啦.cmd命令,输入vu ...
- vue+node.js手把手教你搭建一个直播平台(一)
上一期,帅气的小羽给老铁们简单介绍了项目的功能以及需要用到的一些环境和工具,现在就让我们荡起双桨,撸起袖子,准备开始敲代码啦!!! 先甩锅,小羽主要是搞前端开发的,所以这期张主要讲后端内容,可能讲的不 ...
- vue+node.js手把手教你搭建一个直播平台(三)
上一期,帅气的小羽给老铁们介绍了直播平台的项目的前端框架的搭建,这期就让小羽带大家切图,没错啦,就是老铁们心心念念的切图啦. 补充上期遗漏的内容 但是在正式开启这期内容前,先补充点上期的内容 配置全局 ...
- vue+node.js手把手教你搭建一个直播平台(四)
上一期,帅气的小羽给老铁们介绍了直播平台的项目的前端页面的初步切图,这期就让小羽带大家接入直播相关的api接口.敲黑板!敲黑板!敲黑板!重点来啦~ 1.api接口相关 在src目录下个新建api文件夹 ...
- 手把手教你搭建一个属于自己的Ghost博客
介绍 Ghost 是基于 Node.js 的开源博客平台,由前 WordPress UI 部门主管 John O'Nolan 和 WordPress 高级工程师(女) Hannah Wolfe 创立, ...
- 手把手教你搭建一个中式菜谱知识图谱可视化系统
手把手教你搭建一个中式菜谱知识图谱可视化系统 中式菜谱知识图谱 1.系统功能 2.先来看看效果 实体间关联关系及实体信息显示 不同类型实体开关显示 搜索功能展示 3.系统实现流程 3.1 数据爬取 3 ...
- 手把手教你搭建一个【文件共享平台】系列教程第一话——你想知道的,这里都有
文章目录 Beginning what why how Effect Picture Source Code Ending Beginning 写在最前头(多图慎入).这篇系列教程将手把手(很详细)地 ...
- vue 前端显示图片加token_vue+node.js手把手教你搭建一个直播平台(二)
上一期,帅气的小羽给老铁们介绍了直播平台的项目的后端搭建,这期就让小羽带大家来搭建一下前端的框架. 1.创建前端工程 毫无疑问,搭建一个项目的框架,那第一步肯定是得创建一个工程啦.cmd命令,输入vu ...
- axios下载图片 node_vue+node.js手把手教你搭建一个直播平台(二)
上一期,帅气的小羽给老铁们介绍了直播平台的项目的后端搭建,这期就让小羽带大家来搭建一下前端的框架. 1.创建前端工程 毫无疑问,搭建一个项目的框架,那第一步肯定是得创建一个工程啦.cmd命令,输入vu ...
- 厉害了,手把手教你搭建一个代码在线编辑预览工具
点击下方"前端开发博客",选择"设为星标" 回复"2"加入前端群 简介 大家好,我是一个闲着没事热衷于重复造轮子的不知名前端,今天给大家带来 ...
最新文章
- cocoapods管理第三方框架
- python的工作方向-python工作方向,发展方向?
- HashTable类模板_C++
- guice注入带参构造器_带有Guice的富域模型
- 用python玩转数据慕课答案第三周_大学慕课用Python玩转数据答案公众号
- Composer报错Could not find a matching version of package解决方式
- linux 按日期复制文件夹,Linux 按文件日期分类文件
- Android混淆从入门到精通
- 前端开发学习路线图,完整学习教程+工具+框架
- 支持vxlan的服务器网卡,3台服务器互通vxlan
- 熟练掌握如何设置空闲超时时间.
- 中兴F803/804 ONU实现端口间计算名(基于netbios协议)互通
- 一起来当网管(一)——Windows Server上的DHCP配置
- 华为交换机学习指南基于MAC地址划分VLAN
- 常用思维模式大全(上)
- win10文件夹加密_专业的文件隐藏软件——文件夹隐藏精灵PC软件
- AndrOid系统亭子运行,饼干智能好物开箱 篇二十二:给父母换个手机,让他成楼下凉亭的拍照KOL...
- 异次元发卡网邮箱SMTP配置教程
- SAP调用外围系统接口SXI_MONITOR有显示但是实际上没有调用接口的问题
- wux tab 颜色扩展
热门文章
- 新睿云 亚马逊_一窥新发现的亚马逊欺诈检测器
- java excel 列合并单元格_java怎么操作excel合并单元格
- 用中信证券示范大作手回忆录
- 3D机器学习(4):pytorch入门3:张量的拼接与拆分、张量的运算、张量的统计
- 李白的苏台览古译文赏析
- Centos7做回收站功能,防止误删除
- 爬取https://sc.chinaz.com/tupian/的图片
- html单标签的语法并举例,HTML简介及举例
- 家谱制作软件如何成谱编修流程
- 问卷java_Java 问卷调查