- <div class="tabbar">
- <div class="tabbar_left">
-
- <Breadcrumb />
- div>
- <div class="tabbar_right">
-
- <Setting />
- div>
- div>
-
- <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>
-
- <el-icon style="margin-right: 10px" @click="changeIcon">
-
- 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>
-
- <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>
设置
- <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-form-item>
- <el-form-item label="暗黑模式">
- <el-switch
- v-model="dark"
- class="mt-2"
- style="margin-left: 24px"
- inline-prompt
- active-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>
-
- <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
(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标签是否有类名dark
- dark.value ? (html.className = 'dark') : (html.className = '')
- }
-
- //主题颜色的设置
- const setColor = () => {
- //通知js修改根节点的样式对象的属性与属性值
- const html = document.documentElement
- html.style.setProperty('--el-color-primary', color.value)
- }
- script>
-
- <script lang="ts">
- export default {
- name: 'Setting'
- }
- script>
- <style scoped>style>
- //小仓库:layout组件相关配置仓库
- import { defineStore } from 'pinia'
-
- const useLayOutSettingStore = defineStore('SettingStore', {
- state: () => {
- return {
- fold: false, //用户控制菜单折叠还是收起控制
- refsh: false, //仓库这个属性用于控制刷新效果
- }
- },
- })
-
- export default useLayOutSettingStore
动态判断菜单是否折叠,然后情况修改样式
- <div class="layout_container">
-
- <div
- class="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>
-
- <div
- class="layout_tabbar"
- :class="{ fold: LayOutSettingStore.fold ? true : false }"
- >
- <Tabbar>Tabbar>
- div>
-
- <div
- class="layout_main"
- :class="{ fold: LayOutSettingStore.fold ? true : false }"
- >
- <router-view>router-view>
- div>
- div>
- <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>
-
- <el-icon style="margin-right: 10px" @click="changeIcon">
- <component
- :is="LayOutSettingStore.fold ? 'Fold' : 'Expand'"
- >component>
- el-icon>
-
- <el-breadcrumb separator-icon="ArrowRight">
-
- <el-breadcrumb-item
- v-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>
-
- <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>
设置一个全局变量
- //获取骨架的小仓库
- import useLayOutSettingStore from '@/store/modules/setting'
- const layoutSettingStore = useLayOutSettingStore()
- //刷新按钮点击回调
- const updateRefsh = () => {
- layoutSettingStore.refsh = !layoutSettingStore.refsh
- }
-
- <router-view v-slot="{ Component }">
- <transition name="fade">
-
- <component :is="Component" v-if="flag" />
- transition>
- router-view>
-
- <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 = false
- nextTick(() => {
- flag.value = true
- })
- },
- )
- script>
- <script lang="ts">
- export default {
- // eslint-disable-next-line vue/no-reserved-component-names
- name: '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>
- //全屏按钮点击的回调
- const fullScreen = () => {
- //DOM对象的一个属性:可以用来判断当前是不是全屏模式[全屏:true,不是全屏:false]
- const full = document.fullscreenElement
- //切换为全屏模式
- if (!full) {
- //文档根节点的方法requestFullscreen,实现全屏模式
- document.documentElement.requestFullscreen()
- } else {
- //变为不是全屏模式->退出全屏模式
- document.exitFullscreen()
- }
- }
- //获取用户信息方法
- async userInfo() {
- //获取用户信息进行存储仓库当中[用户头像、名字]
-
- const result: userInfoReponseData = await reqUserInfo()
- console.log(result)
- //如果获取用户信息成功,存储一下用户信息
- if (result.code == 200) {
- this.username = result.data.checkUser.username
- this.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.status
- switch (status) {
- case 401:
- msg = 'token过期'
- break
- case 403:
- msg = '无权访问'
- break
- case 404:
- msg = '请求地址错误'
- break
- case 500:
- msg = '服务器出现问题'
- break
- default:
- msg = '无网络'
- }
- ElMessage({
- type: 'error',
- message: msg
- })
- return Promise.reject(error)
- }
- )
- export default request
- // 存储
- 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 } })
- }
再设置一个退出登录再登录返回原来的路由