父组件
父组件设置相对定位,我的组件设置绝对定位,通过v-bind绑定left偏移量,因为侧边栏会伸缩收回,用watch监听这个变量。
<!--
* @Author: zhangy
* @Date: 2022-06-22 21:16:54
* @LastEditors: zzd993
* @LastEditTime: 2022-08-01 17:10:27
* @FilePath: \elabnote-front-main\src\layout\index.vue
* Copyright (c) 2022 by BMY, All Rights Reserved.
-->
<template>
<div class="main-layout-root">
<a-layout v-if="isLayout" class="layout-main">
<a-layout-sider
:collapsed-width="50"
:default-collapsed="collapsed"
:collapsed="collapsed"
collapsible
class="layout-sider"
>
<Menu :collapsed="collapsed" />
<template #trigger>
<a-space direction="vertical" :size="8">
<a-badge @click="handleMessages" :count="userInfo.unreadCount" dot :offset="[2, -2]">
<IconNotification :style="{ fontSize: '18px', verticalAlign: '-3px' }" />
</a-badge>
<a-avatar @click="showInfo" :size="28" :style="{ background: randomColor }">{{
userInfo.userNameEn
}}</a-avatar>
<div @click="collapsed = !collapsed">
<IconCaretRight v-if="collapsed" />
<IconCaretLeft v-else />
</div>
</a-space>
</template>
</a-layout-sider>
<a-layout v-if="false">
<a-layout>
<a-layout-content>
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
</a-layout-content>
</a-layout>
</a-layout>
<a-layout class="mian-layout-content" ref="MainLayoutContentRef">
<a-layout-sider
:collapsible="false"
:collapsed="isTagViewCollapsed"
:collapsed-width="260"
:width="width"
style="height: 100%; z-index: 2"
@collapse="
() => {
isTagViewCollapsed = !isTagViewCollapsed
}
"
>
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
</a-layout-sider>
<a-layout-content class="tag-view-wrapper">
<!-- <a-ffix :offset-top="0" style="background-color: #f4f5f7"> -->
<TagView style="background-color: #f4f5f7" />
<!-- </a-ffix> -->
<div class="tag-view-detial">
<TagViewDetial />
</div>
</a-layout-content>
</a-layout>
</a-layout>
<router-view v-else v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
<!-- 我的组件 -->
<div class="userInfo">
<person-menu :userInfo="userInfo" v-show="show" />
</div>
</div>
</template>
<script lang="ts" setup>
import { IconCaretRight, IconCaretLeft } from '@arco-design/web-vue/es/icon'
import { ref, watch } from 'vue'
import { getRandomColor } from '@/util'
import { useRoute, useRouter } from 'vue-router'
// import { localCache } from '@/util'
import { useUserStore, useTagViewStore } from '@/store'
import { storeToRefs } from 'pinia'
import Menu from './menu/index.vue'
import TagView from './tag-view/index.vue'
import TagViewDetial from '@/views/tag-view-detial/index.vue'
import { useElementSize } from '@vueuse/core'
import PersonMenu from './person-menu/index.vue'
// 控制信息隐藏显示
let show = ref(false)
const showInfo = () => {
show.value = !show.value
}
const isShowTagView = ref<'none' | 'block'>('none')
const MainLayoutContentRef = ref(null)
const { width } = useElementSize(MainLayoutContentRef)
const { userInfo } = storeToRefs(useUserStore())
// console.log(userInfo)
const { isCollapsed } = storeToRefs(useTagViewStore())
const randomColor = getRandomColor()
const collapsed = ref(true)
const collapsedWidth = ref<string>('60px')
// const popupVisible = ref(false)
const route = useRoute()
const router = useRouter()
const isLayout = ref(true)
const isTagView = ref(false)
const isTagViewCollapsed = ref(true)
// const handleLogout = async () => {
// popupVisible.value = false
// await router.replace('/login')
// localCache.clearCache()
// location.reload()
// }
const handleMessages = async () => {
if (route.path === '/main/vue-app') {
location.hash = '#/message/messageManagement'
} else {
await router.replace('/main/vue-app')
location.hash = '#/message/messageManagement'
}
}
// const handlePersonInfo = async () => {
// if (route.path === '/main/vue-app') {
// location.hash = '#/settings/tips/info'
// } else {
// await router.replace('/main/vue-app')
// location.hash = '#/settings/tips/info'
// }
// popupVisible.value = false
// }
watch(
() => route.path,
() => {
isLayout.value = route?.meta?.isLayout === false ? false : true
isTagView.value = Boolean(route?.meta?.isTagView)
if (!isTagView.value) {
isTagViewCollapsed.value = false
isShowTagView.value = 'none'
} else {
isTagViewCollapsed.value = isCollapsed.value
isShowTagView.value = 'block'
}
},
{
immediate: true
}
)
watch(
isCollapsed,
() => {
if (!isTagView.value) {
isTagViewCollapsed.value = false
} else {
isTagViewCollapsed.value = isCollapsed.value
}
},
{
immediate: true
}
)
/**
* 监听菜单的展开或合并
*/
watch(collapsed, (newCollapsed) => {
newCollapsed ? (collapsedWidth.value = '60px') : (collapsedWidth.value = '210px')
})
</script>
<style scoped lang="scss">
.main-layout-root {
position: relative;
height: 100%;
.userInfo {
position: absolute;
z-index: 100;
left: v-bind(collapsedWidth);
bottom: 60px;
}
}
.layout-main {
height: 100%;
background: var(--color-fill-2);
.layout-sider {
position: relative;
background-color: $themeColor;
:deep(.arco-layout-sider-children) {
height: 95% !important;
.arco-menu-inner {
overflow: hidden;
}
}
:deep(.arco-layout-sider) {
z-index: 1009;
display: flex;
flex-direction: column;
}
}
}
.layout-main :deep(.arco-layout-sider) .logo {
height: 32px;
margin: 8px 0;
background: $themeColor;
}
.layout-main :deep(.arco-layout-sider-light) .logo {
background: $themeColor;
}
.layout-main :deep(.arco-layout-header) {
height: 64px;
line-height: 64px;
background: var(--color-bg-3);
}
.layout-main .layout-sider :deep(.arco-layout-footer) {
height: 48px;
color: var(--color-text-2);
font-weight: 400;
font-size: 14px;
line-height: 48px;
}
.layout-main :deep(.arco-layout-content) {
color: var(--color-text-2);
font-weight: 400;
font-size: 14px;
background: var(--color-bg-3);
}
.layout-main .layout-sider :deep(.arco-layout-footer),
.layout-main .layout-sider :deep(.arco-layout-sider-trigger),
.layout-main .layout-sider :deep(.arco-layout-sider-trigger-light) {
// height: 15%;
flex: 1;
background-color: $themeColor;
border: none;
color: $themeMenuFrontColor;
// layout footer 文字居中
text-align: center;
}
.layout-main .layout-sider :deep(.arco-menu-selected):hover {
background-color: $themeMenuHoverColor;
}
.layout-main .layout-sider :deep(.arco-menu-inline-header):hover {
background-color: $themeMenuHoverColor !important;
}
.layout-main .layout-sider :deep(.arco-menu-item):hover {
display: flex;
background-color: $themeMenuHoverColor !important;
}
.layout-main .layout-sider :deep(.arco-menu-item) {
display: flex;
background-color: $themeColor !important;
color: $themeMenuFrontColor !important;
}
.layout-main .layout-sider :deep(.arco-menu-inline-header) {
background-color: $themeColor !important;
display: flex;
height: 40px;
}
.layout-main .layout-sider :deep(.arco-menu-selected) {
background-color: $themeMenuHoverColor !important;
color: $themeMenuFrontActiveColor !important;
display: flex;
height: 40px;
}
.mian-layout-content {
position: relative;
:deep(.arco-layout-sider) {
position: absolute;
}
:deep(.arco-layout-content) {
// @todo
margin-left: 260px;
// display: v-bind(isShowTagView) !important;
}
:deep(.arco-layout-sider-has-trigger) {
padding-bottom: 0;
}
:deep(.tag-view-wrapper) {
height: 100%;
display: flex;
flex-direction: column;
overflow-y: scroll;
.tag-view-detial {
height: calc(100vh - 38px);
overflow-y: scroll;
flex: 1;
display: flex;
flex-direction: column;
}
}
}
</style>
子组件:
<!--
* @Author: zzd993
* @Date: 2022-07-29 15:00:35
* @LastEditors: zzd993
* @LastEditTime: 2022-08-01 17:54:48
* @FilePath: \elabnote-front-main\src\layout\person-menu\index.vue
* Copyright (c) 2022 by BMY, All Rights Reserved.
-->
<template>
<div class="person-menu">
<div class="person-box">
<a-avatar
:size="40"
:style="{ background: randomColor }"
style="margin-left: 16px; margin-right: 16px; border: 1px solid #fff"
>
{{ props.userInfo.userNameEn }}</a-avatar
>
<div class="person-info">
<span>{{ getGreetings() }} {{ props.userInfo.userNameEn }}</span>
<span>{{ props.userInfo.roleNames }} | {{ props.userInfo.levelTwoOrganizationName }}</span>
</div>
</div>
<a-menu mode="pop" theme="light" class="arco-menu">
<template v-for="menu in menus" :key="menu.id">
<a-menu-item v-if="!menu.children" class="arco-menu-item">
<SvgIcon :icon-size="24" :icon-name="menu.iconName" style="margin-right: 8px" />{{ menu.content }}
</a-menu-item>
<a-sub-menu v-else class="arco-sub-menu">
<template #title>
<SvgIcon :icon-size="24" :icon-name="menu.iconName" style="margin-right: 8px" />{{ menu.content }}
</template>
<a-menu-item v-for="subMenu in menu.children" :key="subMenu.id" class="arco-menu-item">
<SvgIcon :icon-size="24" :icon-name="subMenu.iconName" style="margin-right: 8px" />{{ subMenu.content }}
</a-menu-item>
</a-sub-menu>
</template>
</a-menu>
</div>
</template>
<script setup lang="ts">
import { getRandomColor } from '@/util'
// import { localCache } from '@/util'
import SvgIcon from '@/components/SvgIcon/index.vue'
// import { useRoute, useRouter } from 'vue-router'
// 菜单列表
const menus = [
{
id: '1',
iconName: 'modelset',
content: '模块设置',
children: [
{
id: '6',
iconName: 'kuwei',
content: '库位设置'
},
{
id: '7',
iconName: 'template',
content: '模板设置'
},
{
id: '8',
iconName: 'zhuce',
content: '注册设置'
}
]
},
{
id: '2',
iconName: 'shenpi',
content: '审批设置'
},
{
id: '3',
iconName: 'manage',
content: '管理后台'
},
{
id: '4',
iconName: 'account',
content: '账号设置'
},
{
id: '5',
iconName: 'sign-out',
content: '退出登录'
}
]
const randomColor = getRandomColor()
const props = defineProps<{ userInfo: any }>()
// console.log(props.userInfo)
// const route = useRoute()
// const router = useRouter()
// const popupVisible = ref(false)
// const handlePersonInfo = async () => {
// if (route.path === '/main/vue-app') {
// location.hash = '#/settings/tips/info'
// } else {
// await router.replace('/main/vue-app')
// location.hash = '#/settings/tips/info'
// }
// popupVisible.value = false
// }
// const handleLogout = async () => {
// popupVisible.value = false
// await router.replace('/login')
// localCache.clearCache()
// location.reload()
// }
// 问候语
const getGreetings = () => {
let greeting = ''
let now = new Date(),
hour = now.getHours()
if (hour < 6) {
greeting = '凌晨好'
} else if (hour < 9) {
greeting = '早上好'
} else if (hour < 12) {
greeting = '上午好'
} else if (hour < 14) {
greeting = '中午好'
} else if (hour < 17) {
greeting = '下午好'
} else if (hour < 19) {
greeting = '傍晚好'
} else if (hour < 22) {
greeting = '晚上好'
}
return greeting
}
</script>
<style scoped lang="scss">
.person-menu {
z-index: 99;
border-radius: 6px;
/* .arco-menu-item {
} */
.person-box {
width: 260px;
height: 76px;
display: flex;
background-image: url('../../assets/images/userInfo.png');
/* justify-content: center; */
align-items: center;
.person-info {
display: flex;
flex-direction: column;
span:first-child {
font-weight: 700;
font-size: 14px;
line-height: 22px;
color: #fff;
}
span:nth-child(2) {
font-size: 12px;
line-height: 22px;
color: #c2cdff;
}
}
}
/* .arco-menu {
} */
.arco-sub-menu .arco-menu-item {
width: 128px;
}
}
</style>