对layout界面的搭建
1.logo组件的封装
将右侧的图标和标题封装到一个ts文件
新建layout/logo/index.vue,存放左侧标题与图片
<template>
<div class="logo" v-if="setting.logoHidden">
<img :src="setting.logo" alt="" >
<p>{{setting.title}}</p>
</div>
</template>
<script setup lang="ts">
//引入设置标题与logo配置文件
import setting from '@/setting';
</script>
<style scoped lang="scss">
.logo {
width: 100%;
height: $base-menu-logo-height;
color: white;
display: flex;
align-items: center;
padding: 20px;
img {
width: 40px;
height: 40px;
}
p {
font-size: $base-logo-title-fontSize;
margin-left: 10px;
}
}
</style>
TIPS:双大括号 {{ }} 是用来进行文本插值的语法
在layout/index.vue引入左侧菜单logo子文件
<!-- 左侧菜单 -->
<div class="layout_slider">
<Logo></Logo>
</div>
import Logo from './logo/index.vue'
新建src/setting.ts,对图片与标题进行封装
// 用于项目logo|标题配置
export default {
title: '硅谷甄选运营平台',//项目标题
logo: '/public/logo.png',//项目logo设置
logoHidden: true//logo组件是否隐藏
}
2.左侧菜单静态搭建
以后的菜单要根据用户的路由进行搭建,本章这里写成静态页面
layout/index.vue
<div class="layout_container">
<!-- 左侧菜单 -->
<div class="layout_slider">
<Logo></Logo>
<!-- 展示菜单 -->
<!-- 滚动组件 -->
<el-scrollbar class="scrollbar">
<!--放置菜单组件 -->
<el-menu background-color=" $base-menu-background" text-color="white">
<el-menu-item index="1">首页</el-menu-item>
<el-menu-item index="2">数据大屏</el-menu-item>
<!-- 折叠菜单 -->
<el-sub-menu index="3">
<template #title>
<span>权限管理</span>
</template>
<el-menu-item index="3-1">用户管理</el-menu-item>
<el-menu-item index="3-2">角色管理</el-menu-item>
<el-menu-item index="3-3">菜单管理</el-menu-item>
</el-sub-menu>
</el-menu>
</el-scrollbar>
</div>
.layout_slider {
// 宽度写成全局变量可以随时改
width: $base-menu-width;
height: 100vh;
background-color: $base-menu-background;
color: white;
.scrollbar {
width: 100%;
height: calc(100vh - $base-menu-logo-height);
}
}
3.递归组件生成动态菜单
上述菜单写的是静态,我们需要根据路由动态生成菜单
可以封装成组件动态生成菜单
新建src/layout/menu/index.vue
在layout/index.vue引入菜单组件
// 引入菜单组件
import Menu from './menu/index.vue'
3.1在登录界面添加二级路由
在router/routers.ts添加二级路由
// 登录成功展示数据的路由
path: '/',
component: () => import('@/layout/index.vue'),
name: 'layout',
meta:{
title:'layout',//菜单标题
hidden:false,
},
children:[{
path:'/home',
component:()=>import('@/views/home/index.vue'),
meta:{
title:'首页',//菜单标题
hidden:false,
}
},{
path:'/ceshi',
component:()=>import('@/views/home/index.vue'),
meta:{
title:'测试',//菜单标题
hidden:false,
}
}
]
3.2 把路由的数组存储到仓库当中
便于菜单组件引入
在store/modules/user.ts
// 引入常量路由
import { constantRoute } from '@/router/routes';
挂载到仓库中:
let useUserStore = defineStore('User', {
// 小仓库存储数据的地方
// state函数返回对象的类型没有定义
state: (): UserState => {
return {
token: GET_TOKEN(),//用户唯一标识token
menuRoutes: constantRoute,//仓库存储生成菜单需要数组(路由)
}
},
仓库中没有menuRoutes字段,这个字段是数组,数组存放路由对象,需要定义state数据类型
进入store/modules/types/type.ts文件
import type { RouteRecordRaw } from "vue-router";
// 定义小仓库数据state类型
export interface UserState{
token:string|null;
menuRoutes:RouteRecordRaw[]
}
vue-router提供这个路由对象的类型,引入即可
3.3layout组件获取小仓库的数据
在layout/index.vue引入组件
// 获取用户相关的小仓库
import useUserStore from '@/store/modules/user';
let userStore = useUserStore();
我把你需要的路由数组传给组件menu了
<!-- 根据路由动态生成菜单组件 -->
<Menu :menuList = "userStore.menuRoutes"></Menu>
3.4获取父组件
在layout/menu/index.vue中获取父组件传递传递过来的全部组件
// 获取父组件传过来的所有路由数组
defineProps(['menuList'])
给每一个路由添加路由元信息meta,用来展示路由的标题
meta:{
title:'layout',//菜单标题
hidden:false,
},
撰写菜单界面:
1.通过v-for四次循环遍历一级路由
2.通过递归组件遍历二级路由
<template>
<template v-for="(item, index) in menuList" :key="item.path">
<!-- 没有子路由 -->
<template v-if="!item.children">
<el-menu-item :index="item.path" v-if="!item.meta.hidden">
<!-- 具名插槽 -->
<template #title>
<span>图标  </span>
<span>{{ item.meta.title }}</span>
</template>
</el-menu-item>
</template>
<!-- 有子路由但是只有一个 -->
<template v-if="item.children && item.children.length == 1">
<el-menu-item :index="item.children[0].path" v-if="!item.children[0].meta.hidden">
<template #title>
<span>{{ item.children[0].meta.title }}</span>
</template>
</el-menu-item>
</template>
<!-- 有子路由不止一个 -->
<template>
</template>
<el-sub-menu :index="item.path" v-if="item.children && item.children.length > 1">
<template #title>
<span>{{ item.meta.title }}</span>
</template>
<!-- 递归组件必须要有名字 -->
<Menu :menuList="item.children"></Menu>
</el-sub-menu>
</template>
</template>
(注意:递归组件一定要有名字)
<script lang="ts">
export default {
name: 'Menu'
}
</script>
小细节:取消右侧白色边框
el-menu在.scrollbar属性下面,添加border-right: none;
.scrollbar {
width: 100%;
height: calc(100vh - $base-menu-logo-height);
.el-menu{
border-right: none;
}
}
并不是所有的路由都在菜单里面展示,在路由元信息添加属性hidden,是否隐藏
会有两个判断,一个判断是否有二级路由 一个判断是否隐藏,解决方法是在标签外置一个标签template,放置判断语句
<template v-if="!item.children">
<el-menu-item :index="item.path" v-if="!item.meta.hidden">
4.菜单图标完成
将element-plus图标变成全局组件,这样可以在项目所有地方任意使用
element官网有具体步骤
1.在component/index.ts文件注册所有图标
// 引入element-plus提供的图标组件
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
// 将element-plus图标注册为全局组件
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
}
2.给每个路由添加图标字段
router/routers.ts
{
// 登录路由
path: '/login',
component: () => import('@/views/login/index.vue'),
name: 'login',//命名路由
meta:{
title:'登录',//菜单标题
hidden:true,//代表路由标题在菜单中是否影藏
icon:"Promotion"//菜单文字左侧图标,支持element-plus全部图标
}
},
3.menu/index.vue中写入图标组件
使用全局组件 component加载图标
<el-icon>
<component :is="item.meta.icon"></component>
</el-icon>
4.menu-item点击事件进行路由跳转
折叠图标没有点击事件
<el-menu-item :index="item.path" v-if="!item.meta.hidden" @click="goRoute">
// 点击菜单的回调
const goRoute=(vc:any)=>{
console.log(vc.index);
}
5.项目全部路由配置
在views 新建acl和product文件夹放置界面
在routes.ts文件里配置路由
{
path: '/screen',
component: () => import('@/views/screen/index.vue'),
name: 'Screen',
meta: {
title: '数据大屏',//菜单标题
hidden: false,
icon: "DataBoard"
}
},
{
path: '/acl',
component: () => import('@/layout/index.vue'),
name: 'Acl',
meta: {
title: '权限管理',//菜单标题
hidden: false,
icon: "Lock"
},
children: [{
path: '/acl/user',
component: () => import('@/views/acl/user/index.vue'),
name: 'User',
meta: {
title: '用户管理',//菜单标题
hidden: false,
icon: "User"
}
}, {
path: '/acl/role',
component: () => import('@/views/acl/role/index.vue'),
name: 'Role',
meta: {
title: '权限管理',//菜单标题
hidden: false,
icon: "UserFilled"
}
}, {
path: '/acl/permission',
component: () => import('@/views/acl/permission/index.vue'),
name: 'Permission',
meta: {
title: '菜单管理',//菜单标题
hidden: false,
icon: "Monitor"
}
}
]
},
{
path: '/product',
component: () => import('@/layout/index.vue'),
name: 'Product',
meta: {
title: '商品管理',//菜单标题
hidden: false,
icon: "Goods",
},
children: [{
path: '/product/trademark',
component: () => import('@/views/product/trademark/index.vue'),
name: 'Trademark',
meta: {
title: '品牌管理',//菜单标题
hidden: false,
icon: "ShoppingCartFull"
}
}, {
path: '/product/attr',
component: () => import('@/views/product/attr/index.vue'),
name: 'Attr',
meta: {
title: '属性管理',//菜单标题
icon: "ChromeFilled"
}
}, {
path: '/product/spu',
component: () => import('@/views/product/spu/index.vue'),
name: 'Spu',
meta: {
title: 'SPU管理',//菜单标题
icon: "Calendar"
}
}, {
path: '/product/sku',
component: () => import('@/views/product/sku/index.vue'),
name: 'Sku',
meta: {
title: 'SKU管理',//菜单标题
icon: "Orange"
}
}
]
在menu/index.vue文件写路由跳转,通过点击事件进行跳转@click=“goRoute”
使用push方法
import { useRouter } from 'vue-router';
// 获取路由器对象
let $router = useRouter();
// 点击菜单的回调
const goRoute=(vc:any)=>{
// 路由跳转
$router.push(vc.index);
}
展示内容区域原来是router-view,现在将他封装成组件main
1.引入
// 引入菜单组件
import Menu from './menu/index.vue'
<div class="layout_main">
<Main></Main>
</div>
可以在main组件加入一些过渡动效
在vue官网查看vue-router–进阶—过渡动效
<template>
<div>
<!-- 路由组件出口的位置 -->
<router-view v-slot="{ Component }">
<transition name="fade">
<!-- 渲染layout一级组件的子路由 -->
<component :is="Component" />
</transition>
</router-view>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
.fade-enter-from {
opacity: 0;
transform: scale(0);
}
.fade-enter-active {
transition: all .3s;
}
.fade-enter-to {
opacity: 1;
transform: scale(1);
}
</style>
小细节:
1.menu菜单属性:collapse折叠
2.如果展示的时候是二级路由的界面,刷新完之后仍不变:使用方法default-active:页面加载时默认激活菜单的 index,他们的index就是路由的路径地址