vue3后台管理系统之顶部tabbar组件搭建

1.1静态页面搭建

<template><div class="tabbar"><div class="tabbar_left"><!-- 面包屑 --><Breadcrumb /></div><div class="tabbar_right"><!-- 设置 --><Setting /></div></div>
</template><script setup lang="ts">
import Breadcrumb from './breadcrumb/index.vue'
import Setting from './setting/index.vue'
</script>
<script lang="ts">
export default {name: 'Tabbar',
}
</script>
<style scoped lang="scss">
.tabbar {width: 100%;height: 100%;display: flex;justify-content: space-between;// background-image: linear-gradient(to right, rgb(232, 223, 223), rgb(201, 178, 178), rgb(197, 165, 165));.tabbar_left {display: flex;align-items: center;margin-left: 20px;}.tabbar_right {display: flex;align-items: center;}
}
</style>

面包屑

<template><!-- 顶部左侧静态 --><el-icon style="margin-right: 10px" @click="changeIcon"><!-- <component :is="LayOutSettingStore.fold ? 'Fold' : 'Expand'" /> --></el-icon><!-- 左侧面包屑 --><el-breadcrumb separator-icon="ArrowRight"><!-- 面包动态展示路由名字与标题 --><el-breadcrumb-item v-for="(item, index) in $route.matched" v-show="item.meta.title" :key="index" :to="item.path"><!-- 图标 --><el-icon><component :is="item.meta.icon" /></el-icon><!-- 面包屑展示匹配路由的标题 --><span>{{ item.meta.title }}</span></el-breadcrumb-item></el-breadcrumb>
</template><script setup lang="ts">
import { useRoute } from 'vue-router'
// import useLayOutSettingStore from '@/store/moudles/setting'
// //获取layout配置相关的仓库
// const LayOutSettingStore = useLayOutSettingStore()
//获取路由对象
const $route = useRoute()
console.log($route.matched, '111')//点击图标的方法
const changeIcon = () => {//图标进行切换LayOutSettingStore.fold = !LayOutSettingStore.fold
}
</script>
<script lang="ts">
export default {name: 'Breadcrumb'
}
</script><style scoped></style>

设置

<template><el-button size="small" icon="Refresh" circle @click="updateRefsh" /><el-button size="small" icon="FullScreen" circle @click="fullScreen" /><el-popover placement="bottom" title="主题设置" :width="300" trigger="hover"><!-- 表单元素 --><el-form><el-form-item label="主题颜色"><!-- <el-color-picker v-model="color" size="small" show-alpha :predefine="predefineColors" @change="setColor" /> --></el-form-item><el-form-item label="暗黑模式"><el-switchv-model="dark"class="mt-2"style="margin-left: 24px"inline-promptactive-icon="MoonNight"inactive-icon="Sunny"@change="changeDark"/></el-form-item></el-form><template #reference><el-button size="small" icon="Setting" circle /></template></el-popover><img :src="userStore.avatar" style="width: 24px; height: 24px; margin: 0px 10px; border-radius: 50%" /><!-- 下拉菜单 --><el-dropdown><span class="el-dropdown-link">admin<el-icon class="el-icon--right"><arrow-down /></el-icon></span><template #dropdown><el-dropdown-menu><el-dropdown-item @click="logout">退出登录</el-dropdown-item></el-dropdown-menu></template></el-dropdown>
</template><script setup lang="ts">
import { ref } from 'vue'
// import { useRouter, useRoute } from 'vue-router'
//获取用户相关的小仓库
import useUserStore from '@/store/modules/user'
//获取骨架的小仓库
// import useLayOutSettingStore from '@/store/modules/setting'
// const layoutSettingStore = useLayOutSettingStore()
const userStore = useUserStore()
//获取路由器对象
// let $router = useRouter()
//获取路由对向
// let $route = useRoute()
//收集开关的数据
const dark = ref<boolean>(false)
//刷新按钮点击回调
const updateRefsh = () => {layoutSettingStore.refsh = !layoutSettingStore.refsh
}
//全屏按钮点击的回调
const fullScreen = () => {//DOM对象的一个属性:可以用来判断当前是不是全屏模式[全屏:true,不是全屏:false]const full = document.fullscreenElement//切换为全屏模式if (!full) {//文档根节点的方法requestFullscreen,实现全屏模式document.documentElement.requestFullscreen()} else {//变为不是全屏模式->退出全屏模式document.exitFullscreen()}
}
//退出登录点击回调
const logout = async () => {//第一件事情:需要向服务器发请求[退出登录接口]******//第二件事情:仓库当中关于用于相关的数据清空[token|username|avatar]//第三件事情:跳转到登录页面//跳转到登录页面
}//颜色组件组件的数据
const color = ref('rgba(255, 69, 0, 0.68)')
const predefineColors = ref(['#ff4500','#ff8c00','#ffd700','#90ee90','#00ced1','#1e90ff','#c71585','rgba(255, 69, 0, 0.68)','rgb(255, 120, 0)','hsv(51, 100, 98)','hsva(120, 40, 94, 0.5)','hsl(181, 100%, 37%)','hsla(209, 100%, 56%, 0.73)','#c7158577'
])//switch开关的chang事件进行暗黑模式的切换
const changeDark = () => {//获取HTML根节点const html = document.documentElement//判断HTML标签是否有类名darkdark.value ? (html.className = 'dark') : (html.className = '')
}//主题颜色的设置
const setColor = () => {//通知js修改根节点的样式对象的属性与属性值const html = document.documentElementhtml.style.setProperty('--el-color-primary', color.value)
}
</script><script lang="ts">
export default {name: 'Setting'
}
</script>
<style scoped></style>

1.2菜单折叠效果实现

//小仓库:layout组件相关配置仓库
import { defineStore } from 'pinia'const useLayOutSettingStore = defineStore('SettingStore', {state: () => {return {fold: false, //用户控制菜单折叠还是收起控制refsh: false, //仓库这个属性用于控制刷新效果}},
})export default useLayOutSettingStore

动态判断菜单是否折叠,然后情况修改样式

<template><div class="layout_container"><!-- 左侧导航 --><divclass="layout_slider":class="{ fold: LayOutSettingStore.fold ? true : false }"><Logo /><!-- 展示菜单 --><!-- 滚动组件 --><el-scrollbar class="scrollbar"><!-- 菜单组件--><el-menu:collapse="LayOutSettingStore.fold ? true : false":default-active="$route.path"background-color="#001529"text-color="white"active-text-color="yellowgreen"><!-- 根据路由动态生成菜单 --><Menu :menuList="userStore.menuRoutes"></Menu></el-menu></el-scrollbar></div><!-- 顶部导航 --><divclass="layout_tabbar":class="{ fold: LayOutSettingStore.fold ? true : false }"><Tabbar></Tabbar></div><!-- 内容展示区 --><divclass="layout_main":class="{ fold: LayOutSettingStore.fold ? true : false }"><router-view></router-view></div></div>
</template>
<script setup lang="ts">
import Menu from './components/menu/index.vue'
import Logo from './components/logo/index.vue'
import Tabbar from './components/tabbar/index.vue'
//获取用户相关的小仓库
import useUserStore from '@/store/moudules/user'
let userStore = useUserStore()
// 獲取路有對象
import { useRoute } from 'vue-router'
import useLayOutSettingStore from '@/store/moudules/setting'
//获取layout配置仓库
let LayOutSettingStore = useLayOutSettingStore()
//获取路由器
let $route = useRoute()
console.log($route.path)
</script>
<script lang="ts">
export default {name: 'Layout',
}
</script>
<style scoped lang="scss">
.layout_container {width: 100%;height: 100vh;.layout_slider {color: white;width: $base-menu-width;height: 100vh;background: $base-menu-background;transition: all 0.3s;.scrollbar {width: 100%;height: calc(100vh - $base-menu-logo-height);.el-menu {border-right: none;}}}.layout_tabbar {position: fixed;width: calc(100% - $base-menu-width);height: $base-tabbar-height;top: 0px;left: $base-menu-width;transition: all 0.3s;&.fold {width: calc(100vw - $base-menu-min-width);left: $base-menu-min-width;background-color: #fff;}}.layout_main {transition: all 0.3s;position: absolute;width: calc(100% - $base-menu-width);height: calc(100vh - $base-tabbar-height);left: $base-menu-width;top: $base-tabbar-height;padding: 20px;overflow: auto;background-color: yellowgreen;&.fold {width: calc(100vw - $base-menu-min-width);left: $base-menu-min-width;}}
}
</style>

1.3面包屑的实现

<template><!-- 顶部左侧静态 --><el-icon style="margin-right: 10px" @click="changeIcon"><component:is="LayOutSettingStore.fold ? 'Fold' : 'Expand'"></component></el-icon><!-- 左侧面包屑 --><el-breadcrumb separator-icon="ArrowRight"><!-- 面包动态展示路由名字与标题 --><el-breadcrumb-itemv-for="(item, index) in $route.matched":key="index"v-show="item.meta.title":to="item.path"><!-- 图标 --><el-icon><component :is="item.meta.icon"></component></el-icon><!-- 面包屑展示匹配路由的标题 --><span>{{ item.meta.title }}</span></el-breadcrumb-item></el-breadcrumb>
</template><script setup lang="ts">
import { useRoute, useRouter } from 'vue-router'
import useLayOutSettingStore from '@/store/moudules/setting'
//获取layout配置相关的仓库
let LayOutSettingStore = useLayOutSettingStore()
//获取路由对象
let $route = useRoute()
console.log($route)
console.log($route.matched, '111')
let $router = useRouter()
console.log($router, '111')//点击图标的方法
const changeIcon = () => {//图标进行切换LayOutSettingStore.fold = !LayOutSettingStore.fold
}
</script>
<script lang="ts">
export default {name: 'Breadcrumb',
}
</script><style scoped></style>

1.4刷新业务的实现

设置一个全局变量

//获取骨架的小仓库
import useLayOutSettingStore from '@/store/modules/setting'
const layoutSettingStore = useLayOutSettingStore()
//刷新按钮点击回调
const updateRefsh = () => {layoutSettingStore.refsh = !layoutSettingStore.refsh
}

<template><!-- 路由组件出口的位置 --><router-view v-slot="{ Component }"><transition name="fade"><!-- 渲染layout一级路由组件的子路由 --><component :is="Component" v-if="flag" /></transition></router-view>
</template><script setup lang="ts">
import { watch, ref, nextTick } from 'vue'
import useLayOutSettingStore from '@/store/moudules/setting'
let layOutSettingStore = useLayOutSettingStore()//控制当前组件是否销毁重建
let flag = ref(true)//监听仓库内部数据是否发生变化,如果发生变化,说明用户点击过刷新按钮
watch(() => layOutSettingStore.refsh,() => {//点击刷新按钮:路由组件销毁flag.value = falsenextTick(() => {flag.value = true})},
)
</script>
<script lang="ts">
export default {// eslint-disable-next-line vue/no-reserved-component-namesname: 'Main',
}
</script><style scoped>
.fade-enter-from {opacity: 0;transform: scale(0);
}.fade-enter-active {transition: all 0.3s;
}.fade-enter-to {opacity: 1;transform: scale(1);
}
</style>

1.5全屏功能的实现

//全屏按钮点击的回调
const fullScreen = () => {//DOM对象的一个属性:可以用来判断当前是不是全屏模式[全屏:true,不是全屏:false]const full = document.fullscreenElement//切换为全屏模式if (!full) {//文档根节点的方法requestFullscreen,实现全屏模式document.documentElement.requestFullscreen()} else {//变为不是全屏模式->退出全屏模式document.exitFullscreen()}
}

1.6获取用户信息

//获取用户信息方法async userInfo() {//获取用户信息进行存储仓库当中[用户头像、名字]const result: userInfoReponseData = await reqUserInfo()console.log(result)//如果获取用户信息成功,存储一下用户信息if (result.code == 200) {this.username = result.data.checkUser.usernamethis.avatar = result.data.checkUser.avatar}},

import axios from 'axios'
import { ElMessage } from 'element-plus'
//引入用户相关的仓库
import useUserStore from '@/store/modules/user'
//创建axios实例
const request = axios.create({baseURL: import.meta.env.VITE_APP_BASE_URL,timeout: 5000
})
//请求拦截器
request.interceptors.request.use((config) => {//获取用户相关的小仓库:获取仓库内部token,登录成功以后携带给服务器const userStore = useUserStore()if (userStore.token) {config.headers.token = userStore.token}//config配置对象,headers属性请求头,经常给服务器端携带公共参数//返回配置对象return config
})
//响应拦截器
request.interceptors.response.use((response) => {return response.data},(error) => {//处理网络错误let msg = ''const status = error.response.statusswitch (status) {case 401:msg = 'token过期'breakcase 403:msg = '无权访问'breakcase 404:msg = '请求地址错误'breakcase 500:msg = '服务器出现问题'breakdefault:msg = '无网络'}ElMessage({type: 'error',message: msg})return Promise.reject(error)}
)
export default request

1.7退出登录业务

// 存储
export const SET_TOKEN = (token: string) => {localStorage.setItem('TOKEN', token)
}
// 读取
export const GET_TOKEN = () => {return localStorage.getItem('TOKEN')
}
// 移除token
export const REMOVE_TOKEN = () => {localStorage.removeItem('TOKEN')
}
userLogout() {this.token = ''this.username = ''this.avatar = ''REMOVE_TOKEN()},
//退出登录点击回调
const logout = async () => {//第一件事情:需要向服务器发请求[退出登录接口]******//第二件事情:仓库当中关于用于相关的数据清空[token|username|avatar]//第三件事情:跳转到登录页面//跳转到登录页面userStore.userLogout()$router.push({ path: '/login', query: { redirect: $route.path } })
}

再设置一个退出登录再登录返回原来的路由

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

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

相关文章

自动驾驶的未来展望和挑战

自动驾驶技术是一项引人瞩目的创新&#xff0c;将在未来交通领域产生深远影响。然而&#xff0c;随着技术的不断演进&#xff0c;自动驾驶也面临着一系列挑战和障碍。本文将探讨自动驾驶的未来发展方向、技术面临的挑战&#xff0c;以及自动驾驶对社会和环境的潜在影响。 自动驾…

封装一个vue3 Toast组件,支持组件和api调用

先来看一段代码 components/toast/index.vue <template><div v-if"isShow" class"toast">{{msg}}</div> </template><script setup> import { ref, watch } from vue const props defineProps({show: {type: Boolean,def…

docker搭建个人镜像仓库

docker搭建个人镜像仓库 安装registry mkdir docker-registry cd docker-registry mkdir registry mkdr auth vim docker-compose.ymldocker-compose.yml的内容如下&#xff1a; version: 3 services:registry:image: registrycontainer_name: registryvolumes:- ./registry…

GPT带我学-设计模式-10观察者模式

1 请你介绍一下观察者模式 观察者模式&#xff08;Observer Pattern&#xff09;是一种设计模式&#xff0c;它定义了对象之间的一对多依赖关系&#xff0c;当一个对象&#xff08;被观察者&#xff09;的状态发生改变时&#xff0c;所有依赖于它的对象&#xff08;观察者&…

Canvas的缓冲区

Canvas的缓冲区 canvas的绘制缓冲区和显示缓冲区理解为两个容器&#xff0c;它们用于存储绘制结果。绘制缓冲区是用于存储渲染管线生成的像素数据&#xff0c;而显示缓冲区是绘制缓冲区最终的存储位置。 绘制缓冲区&#xff08;Drawing Buffer&#xff09;: 它是在 canvas 元…

JVM 类的加载子系统

文章目录 类的加载过程加载阶段链接阶段初始化 类的加载器测试代码中获取对应的加载器获取加载器加载的路径不同类对应的加载器自定义加载器自定义加载器的方式 获取类的加载器的方式双亲委派机制双亲委派机制的好处 Java 的 SPI 机制1. 接口定义2. 具体实现3. 配置 META-INF/s…

Redis中设置Hash数据类型的过期时间

1 方案 可以先对key进行赋值&#xff0c;然后对key设置一个过期时间。 &#xff08;1&#xff09;依赖 <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.7.3</version></dependency>…

Kubernetes (K8S)概述

目录 1、K8S 是什么&#xff1f; 1.1 作用 1.2 由来 1.3 含义 1.4 官网 2、为什么要用 K8S? 2.1 K8S 解决了裸跑Docker 的若干痛点 2.2 K8S主要功能如下 2.3 K8S 的特性 3、Kubernetes 集群架构与组件 3.1 核心组件 3.1.1 Master 组件 3.1.2 控制器主要包括 3.1…

Spring Cloud Gateway 路由构建器的源码分析

Spring Cloud Gateway 路由构建器的源码分析 文章目录 1. 路由构建器的入口2. 创建路由规则3. 设置路由规则和属性4. 路由过滤器的设置5. 构建和获取路由规则&#xff1a;6. 实例化路由构建器&#xff1a;8. 路由构建器的源码分析8.1 RouteLocator接口8.2 RouteLocatorBuilder…

判断日期区间或季节等

使用JavaScript的Date对象来获取当前日期&#xff0c;并通过比较判断是否在指定的日期范围内&#xff08;如3月16日-9月15日&#xff09;。以下是一个示例代码&#xff1a; var currentDate new Date(); // 获取当前日期 var startRange new Date(currentDate.getFullYear()…

springBoot与Vue共同搭建webSocket环境

欢迎使用Markdown编辑器 你好&#xff01; 这片文章将教会你从后端springCloud到前端VueEleementAdmin如何搭建Websocket 前端 1. 创建websocket的配置文件在utils文件夹下websocket.js // 暴露自定义websocket对象 export const socket {// 后台请求路径url: ,websocketCo…

Android前台服务和通知

前台服务 Android 13及以上系统需要动态获取通知权限。 //android 13及以上系统动态获取通知权限 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {checkPostNotificationPermission(); } private void checkPostNotificationPermission() {if (ActivityCompat.chec…

信息检索与数据挖掘 | 【实验】排名检索模型

文章目录 &#x1f4da;实验内容&#x1f4da;相关概念&#x1f4da;实验步骤&#x1f407;分词预处理&#x1f407;构建倒排索引表&#x1f407;计算query和各个文档的相似度&#x1f407;queries预处理及检索函数&#x1f525;对输入的文本进行词法分析和标准化处理&#x1f…

【Docker】Dockerfile使用技巧

开启Buildkit BuildKit是Docker官方社区推出的下一代镜像构建神器&#xff0c;可以更加快速&#xff0c;有效&#xff0c;安全地构建docker镜像。 尽管目前BuildKit不是Docker的默认构建工具&#xff0c;但是完全可以考虑将其作为Docker&#xff08;v18.09&#xff09;的首选…

一个注解让 Spring Boot 项目接口返回数据脱敏

1 背景 需求是某些接口返回的信息&#xff0c;涉及到敏感数据的必须进行脱敏操作 2 思路 ①要做成可配置多策略的脱敏操作&#xff0c;要不然一个个接口进行脱敏操作&#xff0c;重复的工作量太多&#xff0c;很显然违背了“多写一行算我输”的程序员规范。思来想去&#xff…

css如何将border线加到元素内部,占内边距,不占外边距

要将边框线添加到元素的内部&#xff0c;可以使用CSS的box-sizing属性和内边距&#xff08;padding&#xff09;来实现。 首先&#xff0c;将元素的box-sizing属性设置为border-box。这会使元素的宽度和高度包括边框和内边距在内。例如&#xff1a; .element {box-sizing: bo…

软件工程与计算总结(二十三)软件工程职业基础

本系列最后一更&#xff0c;《软计》系列总结的大结局&#xff01;本栏目告一段落&#xff0c;之后会结合真题和练习题再发布新的总结~ 往期链接&#xff1a; 《软件工程与计算》总结 一.软件工程职业 1.行业的发展 20世纪50年代&#xff1a;计算机还是研究型机器&#xff…

C++中显示构造和隐式构造

截图来源于C primerplus 第六版。

tomcat的负载均衡、动静分离(nginx联动)

动静分离&#xff1a; 访问静态页面和动态页面分开 实现动态和静态页面负载均衡 实验5台虚拟机 一、动态负载均衡 3台虚拟机模拟&#xff1a; 代理服务器&#xff1a;30 tomcat动态页面&#xff1a;21、22 代理服务器&#xff1a; proxy_pass http://tomcat; proxy_set_h…

buuctf[HCTF 2018]WarmUp 1

题目环境&#xff1a; 发现除了表情包&#xff0c;再无其他F12试试发现source.php文件访问这个文件&#xff0c;格式如下&#xff1a;url/source.php回显如下&#xff1a;PHP代码审计&#xff1a; <?php highlight_file(__FILE__); class emmm {public static function ch…