Vue3 + TS + Antd + Pinia 从零搭建后台系统(四) ant-design-vue Layout布局,导航栏,标签页

devtools/2024/11/13 5:17:08/
书接上回本篇主要介绍: Layout布局,导航栏,标签页继续填充

目录

  • 按需引入组件
  • Layout布局,导航栏,标签页
  • css样式

按需引入组件

使用unplugin-vue-components插件完成ant-design-vue组件的按需加载。
前文中已处理过,详情见前文
链接: Vue3 + TS + Antd + Pinia 从零搭建后台系统(一)
此处还需在tsconfig.json同级添加文件 components.d.ts。
tsconfig.json文件配置如下:

{"compilerOptions": {"target": "es2019","module": "esnext","strict": true,"jsx": "preserve","allowJs": true,"importHelpers": true,"moduleResolution": "node","outDir": "temp","resolveJsonModule": true,"experimentalDecorators": true,"esModuleInterop": true,"allowSyntheticDefaultImports": true,"sourceMap": true,"paths": {"@/*": ["src/*"]},"types": ["@intlify/unplugin-vue-i18n/types","vite/client","element-plus/global","@types/qrcode","vite-plugin-svg-icons/client","./components.d.ts"],"baseUrl": "./","lib": ["esnext", "dom", "dom.iterable", "scripthost"]},"include": ["src/types/**/*.ts","src/types/**/*.tsx","src/**/*.ts","src/**/*.tsx","src/**/*.vue","tests/**/*.ts","tests/**/*.tsx","src/components/BpmnEditor/lib/ReadOnly/ReadOnly.js","src/plugin/index.js"],"exclude": ["dist", "node_modules"]
}

Layout布局,导航栏,标签页

这里统一写在layout文件夹下面
此处用到的图标为iconfont图标库中的图标,可替换为ant-design-vue中的图标

index.vue文件:

<Layout style="height: 100%; width: 100%"><!-- 左侧菜单栏 --><Layout-sider:class="collapsed ? 'side-logo' : 'side-title'"v-model:collapsed="collapsed":trigger="null"collapsible><div style="height: 50px"><img class="logo-style" src="../../assets/images/logo.png" /><div v-if="!collapsed" class="title-style">管理平台</div></div><Menuv-model:selectedKeys="selectedKeys"v-model:openKeys="openKeys"theme="dark"mode="inline"><Sub-menu v-for="sub in menuList" :key="sub.path"><template #title><span :class="sub.meta.icon" style="margin-right: 8px"></span><span>{{ !collapsed ? sub.meta.title : "" }}</span></template><Menu-item v-for="item in sub.children" :key="item.path"><span :class="item.meta.icon"></span><Router-link :to="`${sub.path}/${item.path}`">{{ item.meta.title }}</Router-link></Menu-item></Sub-menu></Menu></Layout-sider><!-- 右侧面包屑、标签页、界面 --><Layout><Layout-header style="height: 75px"><div class="layHeader"><div:class="`trigger icon-new ${!collapsed ? 'icon-new-outdent' : 'icon-new-indent'}`"@click="() => (collapsed = !collapsed)"/><!-- separator=">" 设置层级间展示的符号 默认‘/’--><Breadcrumb><Breadcrumb-item v-for="item in breadcrumbList" :key="item.path"><span>{{ item.meta.title }}</span></Breadcrumb-item></Breadcrumb><Dropdown><Button class="icon-new icon-new-user loginOut" type="primary" ghost></Button><template #overlay><Menu><Menu-item>{{ `用户名:${username}` }}</Menu-item><Menu-item @click="loginOut">退出系统</Menu-item></Menu></template></Dropdown></div><div style="display: flex"><span class="icon-new icon-new-doubleleft spanIcon"></span><Tabsv-model:activeKey="activeKey"hide-addtype="editable-card"@edit="onEdit"@tabClick="onTabClick"><Tab-pane v-for="item in tabPanes" :key="item.path" :tab="item.meta.title"> </Tab-pane></Tabs><Dropdown :trigger="['click']"><div class="icon-new icon-new-doubleright spanIcon" ></div><template #overlay><Menu><Menu-item v-for="item in tabPanes" :key="item.path"><Router-link :to="item.path">{{ item.meta.title }}</Router-link></Menu-item></Menu></template></Dropdown><divclass="icon-new icon-new-close-circle spanIcon"title="关闭其他"@click="closeOthers"></div><div class="icon-new icon-new-sync spanIcon" title="刷新" @click="reLoad"></div></div></Layout-header><Layout-content class="content-style"><Router-view /></Layout-content></Layout></Layout>

index.ts文件:

import { defineComponent, reactive, toRefs, watch } from "vue";
import router from "@/router";
import { useUserStore } from "@/pinia/user";export default defineComponent({name: "Layout",setup() {const datas = reactive({selectedKeys: ["BBB"],openKeys: ["/AAA"],collapsed: false,menuList: [] as any,breadcrumbList: [],activeKey: "",tabPanes: [] as any,username: null as any,});const methods = reactive({init() {datas.username = JSON.parse(localStorage.getItem("user") as any).userInfo?.username;datas.menuList = router.options.routes.filter((v: any) => !v.meta.hideInMenu);datas.selectedKeys = [router.currentRoute.value.name];datas.openKeys = [router.currentRoute.value.matched[0].path];datas.breadcrumbList = router.currentRoute.value.matched;},onEdit(val: any) {let lastIndex = 0;if (datas.tabPanes.length > 1) {datas.tabPanes.forEach((item: any, i: number) => {if (item.path == val) {lastIndex = i - 1;}});datas.tabPanes = datas.tabPanes.filter((v: { path: any }) => v.path !== val);if (datas.tabPanes.length && datas.activeKey == val) {if (lastIndex >= 0) {datas.activeKey = datas.tabPanes[lastIndex].path;datas.selectedKeys = [datas.tabPanes[lastIndex].name];router.push(datas.tabPanes[lastIndex].path);} else {datas.activeKey = datas.tabPanes[0].path;datas.selectedKeys = [datas.tabPanes[0].name];}}}},onTabClick(val: any) {router.push(val);},loginOut() {// 使用Pinia中定义的退出系统的方法const userStore = useUserStore();userStore.logoutConfirm();},closeOthers() {datas.tabPanes = datas.tabPanes.filter((v: { path: any }) => v.path == datas.activeKey);},reLoad() {window.location.reload();},});methods.init();watch(() => router.currentRoute.value.matched,(val) => {// 路由变化时,更新面包屑及标签页datas.breadcrumbList = val;datas.activeKey = router.currentRoute.value.path;if (datas.tabPanes.findIndex((v: any) => v.path == router.currentRoute.value.path) == -1) {datas.tabPanes.push(router.currentRoute.value);}},{ immediate: true });return {...toRefs(datas),...toRefs(methods),};},
});

css样式

style文件夹下,创建index.css 、antd.css、 layout.css
index.css
@import './antd.css';a {font-weight: 500;color: #646cff;text-decoration: inherit;
}
a:hover {color: #535bf2;
}body {margin: 0;display: flex;place-items: center;min-width: 320px;min-height: 100vh;
}h1 {font-size: 3.2em;line-height: 1.1;
}.card {padding: 2em;
}#app {margin: 0 auto;
}.main-content {margin: 10px;height: 100%;overflow-y: auto;
}
layout.css 样式
.side-logo {min-width: 60px !important;flex: 0 0 60px !important;
}
.side-title {flex: 0 0 180px !important;min-width: 180px !important;
}
.logo-style {float: left;margin: 4px;width: 40px;
}
.title-style {color: white;font-size: 18px;line-height: 48px;float: left;margin: 4px;font-weight: 700;
}
.trigger {width: 32px;font-size: 18px;line-height: 40px;padding: 0px;cursor: pointer;transition: color 0.3s;margin: 0 6px;
}.trigger:hover {color: #5487eae0 !important;
}
.content-style {margin: 8px;padding: 4px;background: #fff;min-height: 280px;
}
.loginOut {margin: 6px 0px 0;font-size: 15px;cursor: pointer;border-radius: 50% !important;padding: 0px 0px !important;width: 30px;
}
.loginOut:hover {color: #5487eae0 !important;
}
.fade-enter-active .fade-leave-active {transition: opacity 0.5s;
}
.layHeader {display: flex;height: 40px;border-bottom: 1px solid #05050530;
}
.spanIcon {width: 32px;height: 32px;border: 1px solid #05050530;padding: 8px 6px;opacity: 0.5;line-height: 14px;
}
.msg-style {background-color: #5487eae0;
}
.collased-menu-dropdown {transition: background 0.2s ease-in-out;
}
antd.css 调整组件库中的样式
.ant-btn {font-size: 14px !important;height: 28px !important;padding: 0px 10px !important;border-radius: 4px !important; margin: 2px 8px 2px 0px;
}
.ant-btn::before {margin: 4px;
}
.ant-btn:hover { opacity: 0.8;
}
.ant-form-inline .ant-form-item {margin: 0 8px 0 0 !important;
}
.ant-menu-dark .ant-menu-item-selected {border-radius: 4px !important; 
}
.ant-layout .ant-layout-header {padding-inline: 3px !important;background: #fff;
}
.ant-breadcrumb {padding: 8px 0 !important;font-size: 15px !important;width: calc(100% - 80px) !important;height: 50px;
}
.ant-tabs {width: calc(100% - 80px);
}
.ant-tabs-nav {height: 32px !important;margin-bottom: 8px !important;
}
.ant-tabs-nav .ant-tabs-nav-wrap {border-bottom: 1px solid #e6ebf3;
}
.ant-tabs-nav .ant-tabs-tab {border-top-right-radius: 4px !important;border-top-left-radius: 4px !important;padding: 8px 8px !important;
}
.ant-tabs .ant-tabs-tab-remove {margin: 2px -4px 0px 4px !important;
}
.ant-modal .ant-modal-header {margin-bottom: 20px;
}

项目效果图:
在这里插入图片描述

项目至此基本搭建结束。后续优化或添加功能,不定期更新。ヾ(•ω•`)o


http://www.ppmy.cn/devtools/54079.html

相关文章

华为HCIP Datacom H12-821 卷6

1.单选题 下面是一台路由器的部分配置,关于该部分配置描述正确的是,[HUAWEllJip ip-prefix plpermit 10.0.192.0 8 greater-equal 17 less-equal 18 A、10.0.192.0/8 网段内,掩码长度为 20 的路由会匹配到该前缀列表,匹配规则为允许 B、10.0.192.0/8 网段内,掩码长度为…

CompletableFuture 基本用法

一、 CompletableFuture简介 CompletableFuture 是 Java 8 引入的一个功能强大的类&#xff0c;用于异步编程和并发处理。它提供了丰富的 API 来处理异步任务的结果&#xff0c;支持函数式编程风格&#xff0c;并允许通过链式调用组合多个异步操作。 二、CompletableFuture中…

有哪些零售O2O应用模式?如何构建O2O闭环生态系统?

在零售业的演变历程中&#xff0c;O2O模式的兴起标志着一个新时代的开始。这种模式以其创新性&#xff0c;将线上的便捷与线下的实体体验完美融合&#xff0c;为消费者带来了前所未有的购物便利和体验丰富性。随着技术的不断进步和消费者需求的日益多样化&#xff0c;O2O模式已…

AI推介-大语言模型LLMs论文速览(arXiv方向):2024.06.01-2024.06.05

文章目录&#xff5e; 1.Wings: Learning Multimodal LLMs without Text-only Forgetting2.Pre-trained Large Language Models Use Fourier Features to Compute Addition3.LLM-based Rewriting of Inappropriate Argumentation using Reinforcement Learning from Machine Fe…

Windows Server 2022 中文版、英文版下载 (updated Jun 2024)

Windows Server 2022 中文版、英文版下载 (updated Jun 2024) Windows Server 2022 x64, Version 21H2 请访问原文链接&#xff1a;https://sysin.org/blog/windows-server-2022/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.o…

transdreamer 论文阅读笔记

这篇文章是对dreamer系列的改进&#xff0c;是一篇world model 的论文改进点在于&#xff0c;dreamer用的是循环神经网络&#xff0c;本文想把它改成transformer&#xff0c;并且希望能利用transformer实现并行训练。改成transformer的话有个地方要改掉&#xff0c;dreamer用ht…

win10环境配置ollama-ui运行llama3模型

先说我的笔记本电脑配置intel-i7-11390h,4核8处理器&#xff0c;内存16G。显卡NVIDA GeFroce MX450&#xff0c;2G显存&#xff0c;这是一台5000元左右的电脑。 我用它跑roop、sd1.5、ffusion2、ChatTTs还有pythonpytorch的自定义模型&#xff0c;现在用来跑llama3。当然&…

【CT】LeetCode手撕—42. 接雨水

目录 题目1- 思路2- 实现⭐42. 接雨水——题解思路 3- ACM实现 题目 原题连接&#xff1a;42. 接雨水 1- 思路 模式识别&#xff1a;求雨水的面积 ——> 不仅是只求一个比当前元素大的元素&#xff0c;还要求面积 单调栈 应用场景&#xff0c;需要找到左边比当前元素大的…