Vue+Element Plus后台管理主界面搭建实现

​ 续接Django REST Framework,使用Vite构建Vue3的前端项目

1. 后台管理系统主界面框架搭建

  • 后台系统主界面搭建

新建后台管理文件目录

  •  完成后台整体布局
// 1.主界面 index.vue<script setup lang="ts"></script><template><el-container  class="layout"><el-aside width="200px" class="aside">Aside</el-aside><el-container><el-header class="header">Header</el-header><el-main class="main">Main</el-main></el-container></el-container></template><style scoped>
.layout {height: 100%;
}.aside {background-color: #304156;
}
.header {background-color: lightblue;height: 50px;border-bottom: 1px solid #e5e5e5;display: flex;align-items: center;justify-content: space-between;
}
</style>// 2.配置路由
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
import Index from '../layout/index.vue'
const routes: Array<RouteRecordRaw>= [{path: "/",// name: 'Home',component: Index,    },]// 创建一个 vue-router对象
const router = createRouter({history: createWebHistory(),
})// 暴露接口
export default router3.app.vue引入路由
<script setup lang="ts"></script>
<template><router-view></router-view>
</template><style scoped>
#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;
}</style>
  • 后台页面满屏显示
1.style.css 注销 #app{}
2.index.html添加样式
<!doctype html>
<html lang="en"><head><meta charset="UTF-8" /><link rel="icon" type="image/svg+xml" href="/vite.svg" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>后台管理</title></head>
<!--添加样式--><style>html, body,#app{padding: 0px;margin: 0px;height: 100%;width: 100%;}</style><body><div id="app"></div><script type="module" src="/src/main.ts"></script></body>
</html>

  • 侧边栏布局实现 
// Menu.vue<script setup lang="ts"></script><template><el-menu active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical-demo" default-active="2"text-color="#fff"><el-sub-menu index="1"><template #title><el-icon><location /></el-icon><span>基础数据</span></template><el-menu-item index="1-1">院系管理</el-menu-item><el-menu-item index="1-2">专业管理</el-menu-item><el-menu-item index="1-3">学生管理</el-menu-item></el-sub-menu><el-sub-menu index="2"><template #title><el-icon><location /></el-icon><span>学生管理</span></template><el-menu-item index="2-1">学生信息</el-menu-item><el-menu-item index="2-2">学生成绩</el-menu-item><el-menu-item index="2-3">学生照片</el-menu-item></el-sub-menu><el-sub-menu index="3"><template #title><el-icon><location /></el-icon><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-menu-item index="3-4">权限信息</el-menu-item></el-sub-menu><!-- <el-menu-item index="2"><el-icon><icon-menu /></el-icon><span>Navigator Two</span></el-menu-item><el-menu-item index="3" disabled><el-icon><document /></el-icon><span>Navigator Three</span></el-menu-item><el-menu-item index="4"><el-icon><setting /></el-icon><span>Navigator Four</span></el-menu-item> --></el-menu>
</template><style scoped>
.el-menu-item {display: block;text-align: center;
}
</style>
// index.vue 注册
<script setup lang="ts">
// 引入组件
import MenuVue from './menu/Menu.vue';
import HeaderVue from './header/Header.vue';</script><template><el-container  class="layout"><el-aside width="200px" class="aside"><!-- 调用组件 --><MenuVue></MenuVue></el-aside><el-container><el-header class="header"><!-- 调用组件 --><HeaderVue></HeaderVue></el-header><el-main class="main">Main</el-main></el-container></el-container></template><style scoped>
.layout {height: 100%;
}.aside {background-color: #304156;
}
.header {background-color: lightblue;height: 50px;border-bottom: 1px solid #e5e5e5;display: flex;align-items: center;justify-content: space-between;
}
</style>

  • 添加侧边栏Logo
// 新建MenuLogo.vue<script setup lang="ts"></script><template><div class="logo"><!-- 图片 --><img src="../../assets/logo_main.png" alt="Logo"><span class="title">信息管理系统</span></div>
</template><style scoped>
.logo {background-color: #2b2f3a;height: 50px;border: none;line-height: 50px;display: flex;align-items: center;padding-left: 15px;color: #fff;
}
.logo img {width: 32px;height: 32px;margin-right: 12px;
}
.logo span {font-weight: 600;line-height: 50px;font-size: 16px;font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;vertical-align: middle;
}
</style>
// Menu.vue 绑定并注册 MenuLogo
<script setup lang="ts">
import MenuLogo from './MenuLogo.vue';</script><template><!-- 导入Logo组件 --><MenuLogo class="layout-logo"></MenuLogo><el-menu active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical-demo" default-active="2"text-color="#fff"><el-sub-menu index="1"><template #title><el-icon><location /></el-icon><span>基础数据</span></template><el-menu-item index="1-1">院系管理</el-menu-item><el-menu-item index="1-2">专业管理</el-menu-item><el-menu-item index="1-3">学生管理</el-menu-item></el-sub-menu><el-sub-menu index="2"><template #title><el-icon><location /></el-icon><span>学生管理</span></template><el-menu-item index="2-1">学生信息</el-menu-item><el-menu-item index="2-2">学生成绩</el-menu-item><el-menu-item index="2-3">学生照片</el-menu-item></el-sub-menu><el-sub-menu index="3"><template #title><el-icon><location /></el-icon><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-menu-item index="3-4">权限信息</el-menu-item></el-sub-menu><!-- <el-menu-item index="2"><el-icon><icon-menu /></el-icon><span>Navigator Two</span></el-menu-item><el-menu-item index="3" disabled><el-icon><document /></el-icon><span>Navigator Three</span></el-menu-item><el-menu-item index="4"><el-icon><setting /></el-icon><span>Navigator Four</span></el-menu-item> --></el-menu>
</template><style scoped>
.el-menu-item {display: block;text-align: center;
}
.el-menu-vertical-demo:not(.el-menu--collapse) {width: 230px;min-height: 400px;
}.el-menu {border-right: none;
}.el-menu-item {color: #f4f4f5 !important;
}:deep(.el-sub-menu .el-sub-menu__title) {color: #f4f4f5 !important;
}
/* .el-submenu .is-active .el-submenu__title {border-bottom-color: #1890ff;
} */
:deep(.el-menu .el-menu-item) {color: #bfcbd9;
}/* 菜单点中文字的颜色 */
:deep(.el-menu-item.is-active) {color: #409eff !important;
}
/* 当前打开菜单的所有子菜单颜色 */
:deep(.is-opened .el-menu-item) {background-color: #1f2d3d !important;
}
/* 鼠标移动菜单的颜色 */
:deep(.el-menu-item:hover) {background-color: #001528 !important;
}/* Logo CSS部分的动画 */
@keyframes logoAnimation {0% {transform: scale(0);}50% {transform: scale(1);}100% {transform: scale(1);}
}.layout-logo {animation: logoAnimation 1s ease-out;
}
</style>
  • 动态生成侧边栏菜单
// 新建MenuItem.vue
<script setup lang="ts">
// 导入基本模块
import { reactive } from 'vue'; // 初始化构造数据
let menuList = reactive([{path: "/",meta: {title: "首页",icon: "HomeFilled",},},{path: "/baisc",meta: {title: "基础数据",icon: "Setting",},children: [{path: "/basic/faculty",meta: {title: "院系信息",icon: "Ship",},},{path: "/basic/major",meta: {title: "专业信息",icon: "ShoppingBag",},},{path: "/basic/teacher",meta: {title: "教师信息",icon: "ShoppingCartFull",},},],},{path: "/student",meta: {title: "学生管理",icon: "UserFilled",},children: [{path: "/student/info",meta: {title: "学生信息",icon: "VideoCameraFilled",},},{path: "/student/exam",meta: {title: "考试信息",icon: "OfficeBuilding",},},{path: "/student/image",meta: {title: "学生照片",icon: "TakeawayBox",},},],},{path: "/user",meta: {title: "用户角色",icon: "Ticket",},children: [{path: "/user/account",meta: {title: "登录账号",icon: "Coordinate",},},{path: "/user/roles",meta: {title: "角色信息",icon: "CreditCard",},},{path: "/user/menu",meta: {title: "菜单管理",icon: "DeleteLocation",},},{path: "/user/permission",meta: {title: "权限管理",icon: "Goods",},},],},
]);</script><template><template v-for="menu in menuList"><!-- 1.循环遍历menuList2.如果children存在并且不为空及长度大于0,则创建一级菜单,反之则创建多级3. 点击菜单,跳转到对应路径--><el-sub-menu v-if="menu.children && menu.children.length>0" :index="menu.path"><!-- 展示二级菜单第一层 --><template #title><span>{{ menu.meta.title }}</span></template><!-- 展示二级菜单第二层 --><!-- <template v-for="child in menu.children"><el-menu-item :index="child.path"><span>{{ child.meta.title }}</span></el-menu-item></template> --><template #default><el-menu-item v-for="child in menu.children" :key="child.path" :index="child.path"><span>{{ child.meta.title }}</span></el-menu-item></template></el-sub-menu><el-menu-item v-else :index="menu.path" style="text-align: left;"><span>{{ menu.meta.title }}</span></el-menu-item></template></template><style scoped>
.el-menu-item {display: block;text-align: center;padding-right: 80px;
}</style>
// Menu.vue 注册
<script setup lang="ts">
import MenuLogo from './MenuLogo.vue';
import MenuItem from './MenuItem.vue';</script><template><!-- 导入Logo组件 --><MenuLogo class="layout-logo"></MenuLogo><el-menu active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical-demo" default-active="2"text-color="#fff"><MenuItem></MenuItem></el-menu>
</template><style scoped>
.el-menu-item {display: block;text-align: center;
}
.el-menu-vertical-demo:not(.el-menu--collapse) {width: 230px;min-height: 400px;
}.el-menu {border-right: none;
}.el-menu-item {color: #f4f4f5 !important;
}:deep(.el-sub-menu .el-sub-menu__title) {color: #f4f4f5 !important;
}
/* .el-submenu .is-active .el-submenu__title {border-bottom-color: #1890ff;
} */
:deep(.el-menu .el-menu-item) {color: #bfcbd9;
}/* 菜单点中文字的颜色 */
:deep(.el-menu-item.is-active) {color: #409eff !important;
}
/* 当前打开菜单的所有子菜单颜色 */
:deep(.is-opened .el-menu-item) {background-color: #1f2d3d !important;
}
/* 鼠标移动菜单的颜色 */
:deep(.el-menu-item:hover) {background-color: #001528 !important;
}/* Logo CSS部分的动画 */
@keyframes logoAnimation {0% {transform: scale(0);}50% {transform: scale(1);}100% {transform: scale(1);}
}.layout-logo {animation: logoAnimation 1s ease-out;
}
</style>

  • 侧边栏菜单添加图标

安装

npm install @element-plus/icons-vue

全局注册

// main.tsimport { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router' // 导入路由文件
import * as ElementPlusIconsVue from '@element-plus/icons-vue' // 导入所以 icon图标import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css' // 创建app
const app= createApp(App)app.use(router).use(ElementPlus).mount('#app')// 遍历所有 icon将每个图标以组件方式加载到app中
Object.keys(ElementPlusIconsVue).forEach((key) => {app.component(key, ElementPlusIconsVue[key as keyof typeof ElementPlusIconsVue]); // 注册成全局组件
})

使用

// MenuItem.vue
<script setup lang="ts">
// 导入基本模块
import { reactive } from 'vue'; // 初始化数据
let menuList = reactive([{path: "/",meta: {title: "首页",icon: "HomeFilled",},},{path: "/baisc",meta: {title: "基础数据",icon: "Setting",},children: [{path: "/basic/faculty",meta: {title: "院系信息",icon: "Ship",},},{path: "/basic/major",meta: {title: "专业信息",icon: "ShoppingBag",},},{path: "/basic/teacher",meta: {title: "教师信息",icon: "ShoppingCartFull",},},],},{path: "/student",meta: {title: "学生管理",icon: "UserFilled",},children: [{path: "/student/info",meta: {title: "学生信息",icon: "VideoCameraFilled",},},{path: "/student/exam",meta: {title: "考试信息",icon: "OfficeBuilding",},},{path: "/student/image",meta: {title: "学生照片",icon: "TakeawayBox",},},],},{path: "/user",meta: {title: "用户角色",icon: "Ticket",},children: [{path: "/user/account",meta: {title: "登录账号",icon: "Coordinate",},},{path: "/user/roles",meta: {title: "角色信息",icon: "CreditCard",},},{path: "/user/menu",meta: {title: "菜单管理",icon: "DeleteLocation",},},{path: "/user/permission",meta: {title: "权限管理",icon: "Goods",},},],},
]);</script><template><template v-for="menu in menuList"><!-- 1.循环遍历menuList2.如果children存在并且不为空及长度大于0,则创建一级菜单,反之则创建多级3. 点击菜单,跳转到对应路径--><el-sub-menu v-if="menu.children && menu.children.length>0" :index="menu.path"><!-- 展示二级菜单第一层 --><template #title><el-icon><component class="icons" :is="menu.meta.icon"></component></el-icon><span>{{ menu.meta.title }}</span></template><!-- 展示二级菜单第二层 --><!-- <template v-for="child in menu.children"><el-menu-item :index="child.path"><span>{{ child.meta.title }}</span></el-menu-item></template> --><template #default><el-menu-item v-for="child in menu.children" :key="child.path" :index="child.path"><el-icon><component class="icons" :is="child.meta.icon"></component></el-icon><span style="color: aliceblue;">{{ child.meta.title }}</span></el-menu-item></template></el-sub-menu><el-menu-item v-else :index="menu.path" style="text-align: left;"><el-icon><component class="icons" :is="menu.meta.icon"></component></el-icon><span>{{ menu.meta.title }}</span></el-menu-item></template>
</template><style scoped>
.el-menu-item {display: block;text-align: center;padding-right: 80px;
}</style>
  • Header区域基本布局
// 图标组件定义 Collaspe.vue<script setup lang="ts"></script><template><!-- 使用全局定义的折叠图标 --><el-icon><component class="icons" is="Fold"></component></el-icon>
</template><style scoped>
.el-icon{font-style: 22px;margin-right: 10px;
}
</style>// 面包屑导航定义 Bredcum.vue
<script setup lang="ts"></script><template><el-breadcrumb separator="/"><el-breadcrumb-item>首页</el-breadcrumb-item><el-breadcrumb-item>基础数据</el-breadcrumb-item><el-breadcrumb-item>院系管理</el-breadcrumb-item></el-breadcrumb></template><style scoped></style>// 用户下拉框定义 UserInfo.vue
<script setup lang="ts"></script><template><el-dropdown><span class="el-dropdown-link"><el-icon style="margin-right: 5px;"><user-filled /></el-icon>   <span>admin</span><el-icon class="el-icon--right" style="margin-left: 5px;"><arrow-down /></el-icon></span><template #dropdown><el-dropdown-menu><el-dropdown-item>用户信息</el-dropdown-item><el-dropdown-item>修改密码</el-dropdown-item><el-dropdown-item>安全退出</el-dropdown-item><!-- <el-dropdown-item disabled>Action 4</el-dropdown-item><el-dropdown-item divided>Action 5</el-dropdown-item> --></el-dropdown-menu></template></el-dropdown>
</template><style scoped></style>
// 父组件 Header.vue引入
<script setup lang="ts">
// 导入组件
import UserInfo from './UserInfo.vue';
import Collaspe from './Collaspe.vue';
import Bredcum from './Bredcum.vue';
</script><template><!-- 靠着横排显示将两组件放在同一个div中 --><div style="display: flex; align-items: center;"><Collaspe></Collaspe><Bredcum></Bredcum></div><UserInfo></UserInfo>
</template><style scoped></style>

  • 侧边栏收缩思路
控制菜单栏收缩---->Menu.vue---><el-menu :collapse=true></el-menu>
操作菜单栏收缩---->Collapse.vue
// 点击按钮实现切换(true/false) Collapse.vue
<script setup lang="ts">
// 导入vue
import {ref} from 'vue'
let isCollapsed = ref(false)
const changeCollapse = ()=>{isCollapsed.value =!isCollapsed.value console.log(isCollapsed.value )
}</script><template><!-- 使用全局定义的折叠图标 --><el-icon><component class="icons" is="Fold" @click="changeCollapse"></component></el-icon>
</template>
<style scoped>
.el-icon{font-style: 22px;margin-right: 10px;
}
</style>
跨组件传值{父子组件---->直接传值{// 父组件定义传递的值// 导入vueimport {ref} from 'vue'// 定义待传递的值let name = ref('admin')// 传递给子组件<template><UserInfo :username='name'></UserInfo></template>// 子组件接收父组件传递过来的值defineProps<{username: string}>();// 调用值{{ username }}}兄弟组件---->vuex
}

2. Vuex实现组件间的传值

vuex是基于vue框架的一个状态管理库。可以管理复杂应用的数据状态,比如兄弟组件的通信、多层嵌套的组件的传值等等

store---store是yuex的核心对象,它记录了整个vue应用的数据状态以及操作数据的方式。
state---就是store操作的数据状态对象,
mutation---提供了一种简单易用的同步的方式改变state的状态。
getter---获取state中数据对象

  • vuex安装
// 安装最新版 vuex
npm install vuex@next --save// 新建 store文件夹并在文件夹下新建 index.ts导入vuex模块import { createStore } from 'vuex'// 报错:/node_modules/vuex/types/index.d.ts', but this result could not be resolved when respecting package.json "exports". // 解决报错 node_modules\vuex\package.json在exports字段中添加"types": "./types/index.d.ts"
  • store对象创建
// 导入 vuex 模块
import { createStore } from 'vuex'
// 定义实体(存储结构)
export interface MyStore {// 控制侧边栏收缩collapse: boolean,
}// 创建store对象
export const store = createStore<MyStore>({// 初始状态state: {collapse: false, // 侧边栏收缩},//  mutations 用于更改 Vuex 的 store 中的状态mutations: {toggleCollapse(state: MyStore) {state.collapse =!state.collapse},},// actions 用于提交 mutations,可以包含异步操作actions: {toggleCollapse({ commit }) {commit('toggleCollapse')},},// getters 用于获取状态的某些派生数据getters: {// 侧边栏是否收缩isCollapse(state: MyStore) {return state.collapse},},
})
// 暴露
export default store;
  • store对象注册
// 注册到全局变量
import store from './store' // 导入创建的store对象app.use(store).use(router).use(ElementPlus).mount('#app')
  • 侧边栏收缩功能完成
// Menu.vue
// 组件中调用vuex中定义的store
// 导入usestore的方法
import { useStore } from 'vuex'
// 获取当前vuex的store对象
const store = useStore()
// 导入计算
import { computed } from 'vue' 
// 获取store->state中的collapse值
const isCollapse = computed(()=>{return store.getters['isCollapse']
})// 在标签中实现绑定
<el-menu :collapse = isCollapse></el-menu>// 解决侧边栏收缩 logo显示问题 侧边栏不是收缩状态时展示
<MenuLogo class="layout-logo" v-if="!isCollapse"></MenuLogo>// Collaspe.vue
// 导入usestore的方法
import { useStore } from 'vuex'
// 获取当前vuex的store对象
const store = useStore();
// 导入计算
import { computed } from 'vue' 
// 获取store->state中的collapse值
const isCollapse = computed(()=>{return store.getters['isCollapse']
})// 点击切换收缩事件
const changeCollapse=()=>{// 切换collapse的值store.commit('toggleCollapse')
}// 使用三元表达式判断收缩图标,此时全局定义的icon图标将失效需重新导入
import { Fold,Expand } from '@element-plus/icons-vue';
<component class="icons" :is="isCollapse? Fold: Expand " @click="changeCollapse"></component>

3. Vue-router实现侧边栏导航

  • 实现侧边栏导航
// router/index.ts 配置路由const routes: Array<RouteRecordRaw>= [// 首页{path: "/",name: 'Layout',component: Layout,// 自动跳转redirect: '/dashboard',children:[{path: '/dashboard',name: 'Dashboard',component: () => import('../views/index/Dashboard.vue')}]},// 基础数据--->院系信息、专业信息、教师信息{path: '/basic',name: 'Basic',component: Layout,children: [{path: '/basic/faculty',name: 'Faculty',component: () => import('../views/basic/Faculty.vue')},{path: '/basic/major',name: 'Major',component: () => import('../views/basic/Major.vue')},{path: '/basic/teacher',name: 'Teacher',component: () => import('../views/basic/Teacher.vue')}]},// 学生管理{path: '/student',name:'Student',component: Layout,children: [{path: '/student/info',name: 'StudentInfo',component: () => import('../views/student/Info.vue')},{path: '/student/exam',name: 'StudentExam',component: () => import('../views/student/Exam.vue')},{path: '/student/image',name: 'StudentImage',component: () => import('../views/student/Image.vue')}]},// 用户管理{path: '/user',name: 'User',component: Layout,children: [{path: '/user/account',name: 'UserAccount',component: () => import('../views/user/Account.vue')},{path: '/user/roles',name: 'UserRoles',component: () => import('../views/user/Roles.vue')},{path: '/user/menu',name: 'UserMenu',component: () => import('../views/user/Menu.vue')},{path: '/user/permission',name: 'UserPermission',component: () => import('../views/user/Permission.vue')}]}]
// layout/index.vue引入路由在指定区域显示<el-main class="main"><router-view></router-view></el-main>// layout/menu/Menu.vue 配置点击侧边栏切换路由
<el-menu active-text-color="#ffd04b" background-color="#304156" class="el-menu-vertical-demo" default-active="2"text-color="#fff":collapse = isCollapserouter>

4. 捕获路由信息自动生成面包屑导航

  • 自动生成面包屑导航
// 路由添加 meta字段记录标题名const routes: Array<RouteRecordRaw>= [// 首页{path: "/",name: 'Layout',component: Layout,// 自动跳转redirect: '/dashboard',children:[{path: '/dashboard',name: 'Dashboard',component: () => import('../views/index/Dashboard.vue'),meta: { title: '首页' }}]},// 基础数据--->院系信息、专业信息、教师信息{path: '/basic',name: 'Basic',component: Layout,meta: { title: '基础数据' },children: [{path: '/basic/faculty',name: 'Faculty',component: () => import('../views/basic/Faculty.vue'),meta: { title: '院系信息' }},{path: '/basic/major',name: 'Major',component: () => import('../views/basic/Major.vue'),meta: { title: '专业信息' }},{path: '/basic/teacher',name: 'Teacher',component: () => import('../views/basic/Teacher.vue'),meta: { title: '教师信息' }}]},// 学生管理{path: '/student',name:'Student',component: Layout,meta: { title: '学生管理' },children: [{path: '/student/info',name: 'StudentInfo',component: () => import('../views/student/Info.vue'),meta: { title: '学生信息' }},{path: '/student/exam',name: 'StudentExam',component: () => import('../views/student/Exam.vue'),meta: { title: '考试信息' }},{path: '/student/image',name: 'StudentImage',component: () => import('../views/student/Image.vue'),meta: { title: '学生照片' }}]},// 用户管理{path: '/user',name: 'User',component: Layout,meta: { title: '用户角色' },children: [{path: '/user/account',name: 'UserAccount',component: () => import('../views/user/Account.vue'),meta: { title: '登录账号' }},{path: '/user/roles',name: 'UserRoles',component: () => import('../views/user/Roles.vue'),meta: { title: '角色信息' }},{path: '/user/menu',name: 'UserMenu',component: () => import('../views/user/Menu.vue'),meta: { title: '菜单管理' }},{path: '/user/permission',name: 'UserPermission',component: () => import('../views/user/Permission.vue'),meta: { title: '权限管理' }}]}]
// 动态获取面包屑导航标准流程 /layout/header/Bredcum.vue<script setup lang="ts">
import { Ref, ref, watch } from 'vue'// 定义 useRouter模块
import { useRoute,RouteLocationMatched} from "vue-router"
// 定义面包屑集合
const tabs: Ref<RouteLocationMatched[]> = ref([])// 获取路由信息
const route = useRoute();// 函数定义
const getBredCum=()=>{// 在路由中筛选过滤路由匹配信息 --- route.metched --meta --meta.titlelet matched = route.matched.filter(item=>item.meta && item.meta.title)// 获取metched中的第一条 判断是否为首页const first = matched[0]// 判断是否为首页,为首页时将首页绑定在最前边if(first.path !== '/dashboard'){matched = [{path: '/dashboard', meta:{'title':'首页'}} as any].concat(matched)}// 将拼接好的值传递给tabstabs.value = matchedconsole.log(matched)
}getBredCum();watch(()=>route.path, ()=>getBredCum()) // 路由变化时重新获取面包屑
// watch(()=>route.matched, getBredCum, { immediate: true }) // 路由变化时重新获取面包屑</script><template><el-breadcrumb separator="/"><el-breadcrumb-item v-for="item in tabs">{{ item.meta.title }}</el-breadcrumb-item></el-breadcrumb><!-- <el-breadcrumb-item>首页</el-breadcrumb-item><el-breadcrumb-item>基础数据</el-breadcrumb-item><el-breadcrumb-item>院系管理</el-breadcrumb-item> --></template><style scoped></style>

5. 学生信息页面布局

  • 顶部搜索框布局实现
// views/students/info.vue
<script lang="ts" setup>
import { ref, reactive } from "vue"// 定义存储集合
var Data = reactive({// 定义输入的查询条件q_str: ref(""),// 存储从后台获取的所有院系信息FacultyOptions: reactive([{value:1,label:'计算机学院'},{value:2,label:'外语学院'},]),// 存储选择院系后的值FacultySelected: ref(""),// 存储从后台获取的所有专业信息MajorOptions: reactive([{value:1,label:'计算机专业'},{value:2,label:'外语专业'},]),// 存储选择专业后的值MajorSelected: ref("")
})</script><template><!-- 顶部查询区域   styple="display: flax;"横向显示--><el-form :inline="true"  class="demo-form-inline"><el-form-item label="查询条件"><el-input v-model="Data.q_str" placeholder="请输入查询条件" clearable /></el-form-item><!-- 动态获取院系信息 --><el-form-item label="院系"><el-select v-model="Data.FacultySelected" placeholder="请选择院系"><el-option v-for="item in Data.FacultyOptions":key="item.value":label="item.label":value="item.value" /></el-select></el-form-item><!-- 动态获取专业信息 --><el-form-item label="专业"><el-select v-model="Data.MajorSelected" placeholder="请选择专业"><el-option v-for="item in Data.MajorOptions":key="item.value":label="item.label":value="item.value" /></el-select></el-form-item><el-form-item><el-button type="primary"><!-- 引入方法1 --><el-icon><component class="icons" is="Search"></component></el-icon><span>查询</span></el-button><el-button type="primary"><!-- 引入方法2 --><el-icon><Finished /></el-icon><span>全部</span></el-button><el-button type="primary"><el-icon><Pointer /></el-icon><span>添加</span></el-button></el-form-item></el-form>
</template><style scoped>
.demo-form-inline .el-input {--el-input-width: 220px;
}.demo-form-inline .el-select {--el-select-width: 220px;
}
</style>

  • 学生信息详情布局实现 
<script lang="ts" setup>
import { ref, reactive } from "vue"
import {More,Edit,Delete} from "@element-plus/icons-vue"// 定义存储集合
var Data = reactive({// ===表格区域定义====students: reactive([{sno:'95001',name:'张武',gender:'男',birthday: '2001-10-10',faculty: '计算机学院',major:'计算机网络',mobile: '13514623594',email: '123@163.com',address: '郑州市金水区'},{sno:'95001',name:'张武',gender:'男',birthday: '2001-10-10',faculty: '计算机学院',major:'计算机网络',mobile: '13514623594',email: '123@163.com',address: '郑州市金水区'}]),});</script><template><!-- 2.表格信息部分 --><el-table :data="Data.students" stripe border style="width: 100%" :header-cell-style="{ backgroundColor:'#409EFF',color:'#FFF',FontSize:'14px' }"><el-table-column label="序号" type="index" align="center" width="60" /><el-table-column prop="sno" label="学号" align="center" width="80" /><el-table-column prop="name" label="姓名" align="center" width="80" /><el-table-column prop="gender" label="性别" align="center" width="80"  /><el-table-column prop="birthday" label="出生日期" align="center" width="180" /><el-table-column prop="faculty" label="院系" align="center" width="120" /><el-table-column prop="major" label="专业" align="center" width="120" /><el-table-column prop="mobile" label="电话" align="center" width="140" /><el-table-column prop="email" label="Email" align="center" width="180" /><el-table-column prop="address" label="地址" align="center"/><!-- 按钮区域 --><el-table-column label="操作" align="center"><el-button type="primary" :icon="More" circle size="small"/><el-button type="warning" :icon="Edit" circle size="small"/><el-button type="danger" :icon="Delete" circle size="small"/></el-table-column></el-table></template><style scoped>
.demo-form-inline .el-input {--el-input-width: 220px;
}.demo-form-inline .el-select {--el-select-width: 220px;
}</style>
  • 底部分页实现
<script lang="ts" setup>
import { ref, reactive } from "vue"
import {More,Edit,Delete} from "@element-plus/icons-vue"// 定义存储集合
var Data = reactive({// =====分页====// 当前页currentsPage: ref(1),// 每页显示的数据量pageSize: ref(15),// 总数据量所有记录条数total: ref(0),
});// 分页中修改每页的pageSize
const handleSizeChange=()=>{}// 分页中修改每页的currentsPage
const handleCurrentChange=()=>{}
</script><template><!-- 3.分页 currentPage4当前页 pageSize4每页大小 total记录条数 handleSizeChange改变每页大小 handleCurrentChange改变当前页  --><el-pagination style="margin-top: 20px;"backgroundv-model:current-page="Data.currentsPage"v-model:page-size="Data.pageSize":page-sizes="[10, 12, 15, 18,20,25,40,50]"layout="total, sizes, prev, pager, next, jumper":total="Data.total"@size-change="handleSizeChange"@current-change="handleCurrentChange"/>
</template><style scoped>
.demo-form-inline .el-input {--el-input-width: 220px;
}.demo-form-inline .el-select {--el-select-width: 220px;
}</style>
  • Element Plus中文化
// 全局定义
import zhCn from 'element-plus/es/locale/lang/zh-cn' // 导入中文语言包// 创建app
const app= createApp(App)// 添加 locale:zhCn
app.use(store).use(router).use(ElementPlus,{locale:zhCn}).mount('#app')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/395378.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

初识自然语言处理NLP

文章目录 1、简介2、自然语言处理的发展简史3、语言学理论句法学&#xff08;Syntax&#xff09;语义学&#xff08;Semantics&#xff09;语用学&#xff08;Pragmatics&#xff09;形态学&#xff08;Morphology&#xff09; 4、统计与机器学习方法n-gram 模型隐马尔可夫模型…

C++20中的模块

大多数C项目使用多个翻译单元(translation units)&#xff0c;因此它们需要在这些单元之间共享声明和定义(share declarations and definitions)。headers的使用在这方面非常突出。模块(module)是一种language feature&#xff0c;用于在翻译单元之间共享声明和定义。它们是某些…

怎么用云手机进行TikTok矩阵运营

TikTok作为炙手可热的社交媒体巨头&#xff0c;已经吸引了亿万用户的目光。随着科技的飞速发展&#xff0c;云手机的出现为TikTok矩阵运营注入了新的活力。本文将深入探讨云手机在TikTok矩阵运营中的实际应用&#xff0c;并分享一系列高效策略与技巧。 &#xff08;1&#xff0…

DGA上的动态规划

前言&#xff1a;之前都没有写过建模成有向图来动态规划的&#xff0c;但是这个题可以抽象成有向图来做 我们可以用方块的编号和高来确定底下的长和宽 其实这题说白了就是一个记忆化搜索&#xff0c;但是不知道能不能建模出来而已 #define _CRT_SECURE_NO_WARNINGS #include&l…

39.【C语言】指针(重难点)(D)

目录 10.野指针 *定义 *案例 11.野指针规避方法 *初始化 *防止越界 *指针变量不再使用时&#xff0c;及时置NULL&#xff0c;指针使用之前检查有效性 *避免返回局部变量的地址 *assert断言 12.assert断言 *解释 *作用 *优点 *启用assert的开关 往期推荐 承接上篇 38.【C语言】指…

Qt实现类似淘宝商品展示看板功能简版

前一篇文章的简化版本只有浏览功能&#xff0c;前一篇文章链接如下&#xff1a; Qt实现类似淘宝商品看板的界面&#xff0c;带有循环翻页以及点击某页跳转的功能 效果如下&#xff1a; 代码留给有需要的人。 #ifndef ModelDashboardGroup_h__ #define ModelDashboardGroup_…

选择叮咚门铃的材质注意事项

在挑选叮咚门铃时&#xff0c;材质是一个不容忽视的重要因素。合适的材质不仅能确保门铃的耐用性和美观度&#xff0c;还能影响其性能和使用体验。 塑料材质的叮咚门铃是较为常见且经济实惠的选择。它轻巧且易于成型&#xff0c;可以被设计成各种独特的形状和颜色&#xff0c;为…

Java开发笔记--通用基础数据校验的设计

最近在开发一个功能&#xff0c;对排水管网的基础数据(包括管井、管道、泵站&#xff0c;雨水口&#xff0c;雨水口线&#xff0c;泵站&#xff0c;污水处理厂&#xff0c;排口等)的导入进行校验。 以字段为纬度&#xff0c;考虑二个方面的校验&#xff1a;数据库唯一&#xf…

【Windows】如何用防火墙禁用某个软件联网

我们使用一些激活软件时&#xff0c;经常需要防止软件联网造成激活失效&#xff0c;以下说明如何通过防火墙配置屏蔽掉软件联网。 以下说明手动添加防火墙拦截的方法&#xff1a; 使用【WinR】快捷键打开运行窗口然后输入【wf.msc】 点击确定。 点击左侧的出站规则然后点击右…

el-table自动滚动到最底部

我的需求是这样的&#xff0c;因为我的表格是动态的&#xff0c;可以手动新增行&#xff0c;固定表头&#xff0c;而且需要一屏显示&#xff0c;为了方便用户就需要再新增的时候表格自动向上滚动。 差了官方文档后发现有一个属性可以支持 这个属性正是自己需要的&#xff0c;所…

Python面试宝典第30题:找出第K大元素

题目 给定一个整数数组nums&#xff0c;请找出数组中第K大的数&#xff0c;保证答案存在。其中&#xff0c;1 < K < nums数组长度。 示例 1&#xff1a; 输入&#xff1a;nums [3, 2, 1, 5, 6, 4], K 2 输出&#xff1a;5 示例 2&#xff1a; 输入&#xff1a;nums …

Rest风格快速开发

Rest风格开发简介 简单点来说&#xff0c;Rest风格的开发就是让别人不知道你在做什么&#xff0c;以deleteUserById和selectUserById为例&#xff1a; 普通开发&#xff1a;路径 /users/deleteById?Id666 /users/selectById?Id666 别人很容易知道你这是在干什么 Rest风…

JavaScript骚操作媒体查询攻略

背景 一讲到媒体查询&#xff0c;大家首先想到的可能都是都是CSS中media,这也没错&#xff0c;这确实是最常见的媒体查询方式&#xff0c;但是我们今天要讲的不是它&#xff0c;而是大家很少接触到的window.matchMedia()和window.resize 最近在做项目的时候拿到一个需求&…

【Qt】多种控件实现“hello world“

使用编辑框的方式实现"hello wordl" 使用编辑框实现"hello world"的方式有俩种&#xff1a; 单行编辑框&#xff1a;LineEdit多行编辑框&#xff1a;TextEdit 图形化界面 纯代码方式 代码展示&#xff1a; #include "widget.h" #include &qu…

Python实战:基础语法

一、求解列表中的最大元素 import random#定义函数 def get_max(lst):x lst[0] #x存储的是元素的最大值#遍历操作for i in range(1,len(lst)):if lst[i] > x:x lst[i] #对最大值进行重新赋值return x#调用函数 lst [random.randint(1,100) for item in range(10)] print…

YARN 调度器的配置与使用

YARN 调度器的配置与使用 一、启动公平调度器1.1 配置 yarn-site.xml创建 fail-scheduler.xml 文件 二、同步配置文件三、重启启动 YARN 集群四、提交作业五、运行结果 一、启动公平调度器 公平调度器的使用由属性yarn.resourcemanager.scheduler.class的设置所决定。YARN默认…

mybatis-plus雪花算法

苞米豆mybatis-plus已实现雪花算法&#xff0c;若项目中使用雪花算法生成自增主键&#xff0c;可直接引用相关jar实现其工具类&#xff0c;若不想再单独引用jar也可将其Sequence类直接复制到自己项目中定义为工具类使用 官方文档&#xff1a;https://baomidou.com/ Git地址&am…

C++ | Leetcode C++题解之第330题按要求补齐数组

题目&#xff1a; 题解&#xff1a; class Solution { public:int minPatches(vector<int>& nums, int n) {int patches 0;long long x 1;int length nums.size(), index 0;while (x < n) {if (index < length && nums[index] < x) {x nums[i…

基于python的百度迁徙迁入、迁出数据分析(七)

参考&#xff1a;【Python】基于Python的百度迁徙2——迁徙规模指数&#xff08;附代码&#xff09;-CSDN博客 记录于2024年8月&#xff0c;这篇是获取百度迁徙指数&#xff0c;之前我们都在讨论不同城市的迁徙比例关系&#xff0c;这篇我们来获取百度迁徙指数这个数据&#x…

职场要懂“3不急”,否则走不远

在职场中&#xff0c;我们经常会遇到各种各样的人和事&#xff0c;有的同事能够得到领导的重视和喜爱&#xff0c;有的则始终处于“不温不火”的状态&#xff0c;这其中到底是什么原因导致的呢&#xff1f; 其实&#xff0c;很大一部分原因是因为在工作中犯了一些“急于表现”…