vue3中使用ant-design-vue的layout组件实现动态导航栏和面包屑功能
光年在眼前 人气:00 前言
最近在自己搞一个前后端小项目,前端想使用ant-design-vue的layout组件实现动态导航栏和面包屑,但是网上的资料较少,所以我就自己整合实现了一下,在此记录分享。
1 准备工作
基于一个新建的Vue3项目上实现。
1.1 安装ant-design-vue
官方文档:Components Overview - Ant Design Vue (antdv.com)
安装:
npm i --save ant-design-vue
全局注册:
import { createApp } from 'vue'; import Antd from 'ant-design-vue'; import App from './App'; import 'ant-design-vue/dist/antd.css'; const app = createApp(App); app.use(Antd).mount('#app');
1.2 安装图标组件包
npm install --save @ant-design/icons-vue
main.js中引用并全局注册
import * as Icons from '@ant-design/icons-vue' //全局注册图标 const icons = Icons for (const i in icons) { app.component(i, icons[i]) }
2 选择组件
如下图所示,复制组件代码:
3 路由文件
router/index.js文件
import { createRouter, createWebHashHistory } from 'vue-router' const routes = [ { //导航页 path: '/layout', name: 'layout', meta: { title: '首页', keepalive: true }, component: () => import('@/views/layout/'), children: [ { //欢迎页 path: '/layout', name: 'welcome', meta: { title: '首页', keepalive: true }, component: () => import('@/views/welcome/') }, { //实时数据 path: '/runtimeData', name: 'runtimeData', meta: { title: '实时数据', keepalive: true }, component: () => import('@/views/runtimeData/') }, { //数据分析 path: '/dataAnalysis', name: 'dataAnalysis', meta: { title: '数据分析', keepalive: true }, component: () => import('@/views/dataAnalysis/') }, { //数据处理(增删改查) path: '/dataManage', name: 'dataManage', meta: { title: '数据总览', keepalive: true }, component: () => import('@/views/dataManage/') }, { //查看用户信息 path: '/showUserInfo', name: 'showUserInfo', meta: { title: '查看用户信息', keepalive: true }, component: () => import('@/views/my/showUserInfo.vue') }, { //修改用户信息 path: '/editUserInfo', name: 'editUserInfo', meta: { title: '修改用户信息', keepalive: true }, component: () => import('@/views/my/editUserInfo.vue') }, ] }, { //登录页面 path: '/login', name: 'login', meta: { title: '登录', keepalive: true }, component: () => import('@/views/login/index.vue') }, ] const router = createRouter({ history: createWebHashHistory(), routes }) export default router
4 Vue导航页面
views/layout/index.vue,主要关注标签a-layout中的内容及相关变量
<template> <a-layout id="components-layout-demo-custom-trigger" style="min-height: 100vh"> <a-layout-sider v-model:collapsed="collapsed" collapsible> <div class="logo"> 温湿度数据显示 </div> <a-menu @click="navClick" v-model="currentSelectChild" @openChange="onOpenChange" :openKeys="currentParent" :inline-collapsed="collapsed" :selectedKeys="[route.path]" theme="dark" mode="inline" > <template v-for='(item,index) in NavDataInfo.NavData'> <a-sub-menu :key="item.Path" v-if='item.Child.length > 0'> <template #title> <a-icon> <meh-outlined/> </a-icon> <span>{{item.Title}}</span> </template> <a-menu-item v-for="(itChild,ind) in item.Child" :key="itChild.Path"> <a-icon> <meh-outlined/> </a-icon> <router-link :to="itChild.Path"> <!--根据路径去跳转页面--> {{itChild.Title}} </router-link> </a-menu-item> </a-sub-menu> <a-menu-item :key="item.Path" v-else> <a-icon> <meh-outlined/> </a-icon> <router-link :to="item.Path"> <a-icon :type="item.Icons"/> <span>{{item.Title}}</span> </router-link> </a-menu-item> </template> </a-menu> </a-layout-sider> <a-layout> <a-layout-header style="background: #fff; padding: 0"> <div id="header"> <div id="left"> <span>作者:</span> </div> <div id="right"> <a-avatar src="https://joeschmoe.io/api/v1/random"/> <el-dropdown> <span class="el-dropdown-link"> User <el-icon class="el-icon--right"> <arrow-down /> </el-icon> </span> <template #dropdown> <el-dropdown-menu> <el-dropdown-item><router-link to="/showUserInfo">我的信息</router-link></el-dropdown-item> <el-dropdown-item><router-link to="/editUserInfo">修改信息</router-link></el-dropdown-item> <el-dropdown-item><span @click="outLogin">退出登录</span></el-dropdown-item> </el-dropdown-menu> </template> </el-dropdown> </div> </div> </a-layout-header> <!-- <keep-alive>--> <a-layout-content style="margin: 0 16px"> <!-- 面包屑 --> <a-breadcrumb style="margin: 16px 0" separator=">"> <!-- 自定义返回函数 ←--> <a-breadcrumb-item @click="goback"> <a-icon> <import-outlined/> </a-icon> 返回 </a-breadcrumb-item> <a-breadcrumb-item v-for="(item, index) in breadList" :key="item.name"> <router-link v-if="item.name !== name && index !== 1" :to="{ path: item.path === '' ? '/' : item.path }"> {{ item.meta.title }} </router-link> <span v-else> {{ item.meta.title }} </span> </a-breadcrumb-item> </a-breadcrumb> <!-- <transition>--> <div :style="{ padding: '24px', background: '#fff', minHeight: '100%' }"> <router-view/> </div> <!-- </transition>--> </a-layout-content> <!-- </keep-alive>--> <a-layout-footer style="text-align: center"> Great Project ©2022 Created by </a-layout-footer> </a-layout> </a-layout> </template> <script setup> import { ref, reactive, onBeforeMount, watch, createVNode } from 'vue' import { useRouter, useRoute } from 'vue-router' import { Modal, message } from 'ant-design-vue' import { ExclamationCircleOutlined } from '@ant-design/icons-vue' import myRouter from '@/router' import { ArrowDown } from '@element-plus/icons-vue' //************************************************data部分 const route = useRoute() const router = useRouter() const collapsed = ref(false) const selectedKeys = ref(['0']) const name = ref('') const breadList = ref([]) const NavDataInfo = reactive({ NavData: [ { NavID: '0', Icons: 'home', Title: '首页', Path: '/layout', Child: [] }, { NavID: '1', Icons: 'meh', Title: '实时数据', Path: '/runtimeData', Child: [] }, { NavID: '2', Icons: 'like', Title: '数据管理', Path: '/dataManage', Child: [ { NavID: '2-1', Icons: 'man', Title: '数据总览', Path: '/dataManage', Child: [] }, ] }, { NavID: '3', Icons: 'key', Title: '数据分析', Path: '/dataAnalysis', Child: [] }, ], }) //************************************************data部分 //************************************************方法 const getBreadcrumb = () => { breadList.value = [] name.value = route.name route.matched.forEach(item => { breadList.value.push(item) }) console.log(breadList.value) console.log(name.value) console.log(route) } // 返回上一页,调用的组件 router.back(); const goback = () => { //点击了返回按钮 router.back() } //退出登录 const outLogin = () => { Modal.confirm({ title: '您确定要退出登录吗?', icon: createVNode(ExclamationCircleOutlined), content: createVNode('div', { style: 'color:red;', }, '点击OK则将退出!'), onOk () { // console.log('OK', key) message.success('退出登录!') myRouter.push({ path: "/login" }); }, onCancel () { // console.log('Cancel') message.success('取消成功!') }, class: 'test', }) } //监视路由 watch(() => route.path, getBreadcrumb) //*************************************************方法 //*************************************************生命周期 onBeforeMount(() => { getBreadcrumb() }) //*************************************************生命周期 </script> <style scoped> #components-layout-demo-custom-trigger { height: 100%; } #components-layout-demo-custom-trigger .trigger { font-size: 18px; line-height: 64px; padding: 0 24px; cursor: pointer; transition: color 0.3s; } #components-layout-demo-custom-trigger .trigger:hover { color: #1890ff; } #components-layout-demo-custom-trigger .logo { height: 32px; background: rgb(127, 252, 255); margin: 16px; font-size: 20px; text-align: center; font-family: 宋体; } #header { display: flex; height: 70px; /*margin: 0;*/ padding: 0; } #left { width: 80%; /*height: 25px;*/ /*background-color: darksalmon;*/ justify-content: flex-start; display: flex; align-items: center; margin-left: 16px; } #right { flex: 1; width: 20%; /*background-color: coral;*/ /*height: 50px;*/ justify-content: flex-end; display: flex; align-items: center; margin-right: 16px; } .example-showcase .el-dropdown-link { cursor: pointer; color: var(--el-color-primary); display: flex; align-items: center; } </style>
上面的代码中将路由文件中的路由表重新写了一个变量,主要是为了方便,并不是所有页面路由都要制作导航栏,这样就不用在router/index.js中添加路由时考虑太多。
5 最终效果
效果如上图所示,我这里也写了一个面包屑,不过还有些问题,就交给大伙儿实现吧!
加载全部内容