sakura/src/layouts/Base.vue

203 lines
4.9 KiB
Vue
Raw Normal View History

2021-07-09 18:28:29 +08:00
<template>
<div>
<!-- PC -->
<div v-if="!isMobile" class="page">
<header class="header__wrapper">
<Header></Header>
</header>
<div class="header__placeholder" v-if="$props.headerPlaceholder"></div>
<section class="content__wrapper">
<slot></slot>
<footer class="footer__wrapper">
<Footer></Footer>
</footer>
</section>
</div>
2021-08-04 23:57:10 +08:00
<!-- / PC -->
<!-- Mobile -->
<div v-else :class="['page', 'mobile', { 'show-drawer': shouldDrawerOpen }]">
<header class="header__wrapper">
<HeaderMobile :open="shouldDrawerOpen" @toggle="handleMDrawerToggleEvent"></HeaderMobile>
<div class="fake-after" @click="handleClickFakeAfterEvent"></div>
</header>
<div class="header__placeholder mdc-elevation--z4" v-if="$props.headerPlaceholder"></div>
<section class="content__wrapper mdc-elevation--z4">
<slot></slot>
<footer class="footer__wrapper">
<Footer></Footer>
</footer>
<div class="fake-after" @click="handleClickFakeAfterEvent"></div>
</section>
<aside class="drawer__wrapper">
<NavDrawer></NavDrawer>
</aside>
</div>
2021-08-04 23:57:10 +08:00
<!-- / Mobile -->
<div class="go-top__wrapper">
<GoTop :showDrawer="shouldDrawerOpen"></GoTop>
</div>
2021-07-09 18:28:29 +08:00
</div>
</template>
<script lang="ts">
import { defineComponent, computed, onUnmounted, onDeactivated } from 'vue'
2021-07-29 17:41:40 +08:00
import { throttle } from 'lodash'
import {
useState,
useWindowResize,
useKeepAliveWindowScrollTop,
useWindowScrollLock,
} from '@/hooks'
2021-07-09 18:28:29 +08:00
import Header from '@/layouts/components/header/Header.vue'
import Footer from '@/layouts/components/footer/Footer.vue'
import HeaderMobile from '@/layouts/components/header/HeaderMobile.vue'
import NavDrawer from '@/layouts/components/header/NavDrawer.vue'
2021-08-04 23:57:10 +08:00
import GoTop from './components/goTop/GoTop.vue'
2021-07-09 18:28:29 +08:00
export default defineComponent({
name: 'LayoutBase',
2021-08-04 23:57:10 +08:00
components: { Header, Footer, HeaderMobile, NavDrawer, GoTop },
props: { headerPlaceholder: { type: Boolean, default: true } },
setup() {
2021-07-29 17:41:40 +08:00
useKeepAliveWindowScrollTop()
const windowSize = useWindowResize()
const isMobile = computed(() => windowSize.value.innerWidth <= 600)
const [shouldDrawerOpen, setShouldDrawerOpen] = useState(false)
2021-07-29 17:41:40 +08:00
const [removeScrollLock, addScrollLock] = useWindowScrollLock()
const toggleDrawer = throttle(
() => {
setShouldDrawerOpen(!shouldDrawerOpen.value)
if (shouldDrawerOpen.value) {
addScrollLock()
} else {
removeScrollLock()
}
},
500,
{
trailing: false,
}
)
const handleMDrawerToggleEvent = () => {
toggleDrawer()
}
const handleClickFakeAfterEvent = () => {
toggleDrawer()
}
onUnmounted(() => {
setShouldDrawerOpen(false)
})
onDeactivated(() => {
setShouldDrawerOpen(false)
})
return { isMobile, handleMDrawerToggleEvent, shouldDrawerOpen, handleClickFakeAfterEvent }
},
2021-07-09 18:28:29 +08:00
})
</script>
<style lang="scss" scoped>
2021-07-29 17:41:40 +08:00
@use '@/styles/app';
::v-deep() {
@include app.global;
}
$drawer-width: 260px;
2021-07-09 18:28:29 +08:00
.page {
position: relative;
overflow: hidden;
2021-07-09 18:28:29 +08:00
.header__wrapper {
position: fixed;
2021-07-09 18:28:29 +08:00
top: 0;
left: 0;
width: 100%;
height: 48px;
z-index: 2;
}
.header__placeholder {
width: 100%;
height: 48px;
visibility: hidden;
2021-07-09 18:28:29 +08:00
}
.content__wrapper {
2021-07-09 18:28:29 +08:00
position: relative;
z-index: 1;
overflow: hidden;
background: #ffffff;
}
&.mobile {
.header__wrapper {
overflow-x: hidden; // hide box shadow
height: 60px; // left the gap for box shadow
::v-deep() {
.toggler__wrapper {
z-index: 4;
}
}
}
.content__wrapper {
position: relative;
left: 0;
z-index: 1;
}
.header__wrapper,
.content__wrapper {
transition: transform 0.5s;
> .fake-after {
position: absolute;
top: 0;
right: 0;
width: 0;
height: 0;
background: rgba(0, 0, 0, 0.2);
content: '';
opacity: 0;
transition: opacity 0.5s, width 0.1s 0.5s, height 0.1s 0.5s;
z-index: 3;
}
}
.drawer__wrapper {
position: fixed;
top: 0;
left: 0;
width: #{$drawer-width};
height: 100%;
background: #ffffff;
visibility: hidden;
transition: all 0.5s;
z-index: 0;
}
&.show-drawer {
.drawer__wrapper {
visibility: visible;
transition: transform 0.5s;
}
.content__wrapper,
.header__wrapper {
transform: translate3d(#{$drawer-width}, 0, 0);
> .fake-after {
width: 100%;
height: 100%;
opacity: 1;
transition: opacity 0.5s;
}
}
.header__wrapper {
> .fake-after {
height: 48px;
}
}
}
2021-07-09 18:28:29 +08:00
}
}
2021-08-04 23:57:10 +08:00
.go-top__wrapper {
--drawer-width: #{$drawer-width};
}
2021-07-09 18:28:29 +08:00
</style>