重构 Header.vue-tailwind

This commit is contained in:
2024-09-29 00:55:06 +08:00
parent f9a7c0c5c4
commit e8bea369b8

View File

@@ -1,56 +1,58 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted } from 'vue'; import { ref, onMounted, onUnmounted } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
const router = useRouter() const router = useRouter()
const showMoreOptions = ref(false);
interface MoreOptionsVisable { const moreOptionsButton = ref<HTMLElement | null>(null);
moreOptions: HTMLElement | null; const handleMoreOptionsButtonClick = () => {
show(): void; showMoreOptions.value = !showMoreOptions.value;
hidden(): void;
toggle(): void;
} }
const handleScreenResize = (e: MediaQueryListEvent) => {
const moreOptionsVisable: MoreOptionsVisable = { if (e.matches)
moreOptions: null, showMoreOptions.value = false;
show() {
if (!this.moreOptions)
throw new Error('moreOptions元素不存在');
this.moreOptions.classList.remove('header-right-hidden');
},
hidden() {
if (!this.moreOptions)
throw new Error('moreOptions元素不存在');
this.moreOptions.classList.add('header-right-hidden');
},
toggle() {
if (!this.moreOptions)
throw new Error('moreOptions元素不存在');
this.moreOptions.classList.toggle('header-right-hidden')
}
} }
onMounted(async () => { onMounted(async () => {
moreOptionsVisable.moreOptions = document.querySelector("#header-right"); if (moreOptionsButton.value) {
moreOptionsButton.value.addEventListener('click', handleMoreOptionsButtonClick)
}
const mediaQueryList = window.matchMedia('(min-width: 640px)');
mediaQueryList.addEventListener('change', handleScreenResize);
if (mediaQueryList.matches)
showMoreOptions.value = false;
}); });
onUnmounted(async () => {
if (moreOptionsButton.value) {
moreOptionsButton.value.removeEventListener('click', handleMoreOptionsButtonClick);
}
const mediaQueryList = window.matchMedia('(min-width: 640px)');
mediaQueryList.removeEventListener('change', handleScreenResize);
})
router.afterEach(() => { router.afterEach(() => {
moreOptionsVisable.hidden(); showMoreOptions.value = false;
}); });
</script> </script>
<template> <template>
<div class="main-container"> <div class="z-[500] w-full fixed backdrop-blur-sm bg-white/60">
<div class="header-container"> <div class="w-full box-content mx-auto py-[15px] sm:py-[22px] max-w-[1170px] flex justify-between items-center transition-all duration-200 border-b-[1px] border-b-[#eee]"
<div class="header-left"> :class="[{ 'flex-col': showMoreOptions }]">
<!-- left header -->
<div class="px-[25px] flex items-center w-full justify-between sm:block">
<div> <div>
<RouterLink :to="{ name: 'home' }" v-if="$route.name == 'home'"> <RouterLink :to="{ name: 'home' }" v-if="$route.name == 'home'">
<div class="emoji">🍭</div> <div class="h-[35px] text-[25px] cursor-pointer]">🍭</div>
</RouterLink> </RouterLink>
<RouterLink :to="{ name: 'home' }" v-else> <RouterLink :to="{ name: 'home' }" v-else>
<div class="title">特恩(TONE)</div> <div class="h-[35px] leading-[35px] font-semibold tracking-[5px] text-[#333] text-nowrap">
特恩(TONE)</div>
</RouterLink> </RouterLink>
</div> </div>
<!-- 更多选项按钮宽度小于800时出现 --> <!-- 更多选项按钮宽度小于800时出现 -->
<div class="more" tabindex="0" id="header-more" @click="moreOptionsVisable.toggle"> <div class="sm:hidden block" tabindex="0" id="header-more" ref="moreOptionsButton">
<svg t="1705913460674" class="icon" viewBox="0 0 1024 1024" version="1.1" <svg t="1705913460674" class="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="10513" width="20" height="20"> xmlns="http://www.w3.org/2000/svg" p-id="10513" width="20" height="20">
<path <path
@@ -59,161 +61,33 @@ router.afterEach(() => {
</svg> </svg>
</div> </div>
</div> </div>
<div class="header-right header-right-hidden" id="header-right"> <!-- right header -->
<div class="link-list"> <div class="sm:block" :class="[{ 'hidden': !showMoreOptions }, { 'mt-[25px]': showMoreOptions }]"
<RouterLink :to="{ name: 'resource' }" v-show="true"> id="header-right">
<div class="link" :class="{ 'link-chosen': $route.name === 'resource' }">资源</div> <div class="flex justify-end items-center">
<RouterLink :to="{ name: 'resource' }">
<div class="text-nowrap mx-[20px] cursor-pointer text-[#666] transition-all duration-200 border-b-[3px] border-b-transparent hover:text-black"
:class="{ 'border-b-[#e03ebf] text-black': $route.name === 'resource' }">资源</div>
</RouterLink> </RouterLink>
<RouterLink :to="{ name: 'download' }" v-show="true"> <RouterLink :to="{ name: 'download' }">
<div class="link" :class="{ 'link-chosen': $route.name === 'download' }">下载</div> <div class="text-nowrap mx-[20px] cursor-pointer text-[#666] transition-all duration-200 border-b-[3px] border-b-transparent hover:text-black"
:class="{ 'border-b-[#e03ebf] text-black': $route.name === 'download' }">下载</div>
</RouterLink> </RouterLink>
<RouterLink :to="{ name: 'blog' }" v-show="true"> <RouterLink :to="{ name: 'blog' }">
<div class="link" :class="{ 'link-chosen': $route.name === 'blog' || $route.name === 'blogContent' }">博客</div> <div class="text-nowrap mx-[20px] cursor-pointer text-[#666] transition-all duration-200 border-b-[3px] border-b-transparent hover:text-black"
:class="{ 'border-b-[#e03ebf] text-black': $route.name === 'blog' || $route.name === 'blogContent' }">
博客</div>
</RouterLink> </RouterLink>
<RouterLink :to="{ name: 'dashboard' }" v-show="true"> <RouterLink :to="{ name: 'dashboard' }">
<div class="link" <div class="text-nowrap mx-[20px] cursor-pointer text-[#666] transition-all duration-200 border-b-[3px] border-b-transparent hover:text-black"
:class="{ 'link-chosen': $route.name === 'login' || $route.name === 'dashboard' }">控制台</div> :class="{ 'border-b-[#e03ebf] text-black': $route.name === 'login' || $route.name === 'dashboard' }">
控制台</div>
</RouterLink> </RouterLink>
</div> </div>
</div> </div>
</div> </div>
<div class="header-divider"></div>
</div> </div>
<div class="main-container-block"></div> <!-- 占位盒用于解决fixed布局导致的文档流异常 -->
<div class="h-[66px] sm:h-[80px] w-full transition-all duration-200"></div>
</template> </template>
<style scoped> <style scoped></style>
.main-container {
/* height: 69px; */
z-index: 500;
width: 100%;
position: fixed;
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
background-color: rgba(255, 255, 255, 0.6);
}
.header-container {
/* height: 100%; */
width: 100%;
margin: 0 auto;
padding: 22px 0;
max-width: 1170px;
display: flex;
justify-content: space-between;
align-items: center;
transition: padding 0.2s;
}
.header-left,
.header-right {
margin: 0 25px;
}
.header-left .emoji {
font-size: 25px;
cursor: pointer;
height: 35px;
}
.header-left .title {
/* 因为棒棒糖的高度为35需要保持统一 */
height: 35px;
line-height: 35px;
font-size: 18px;
font-weight: 600;
letter-spacing: 5px;
cursor: pointer;
color: #333;
}
.header-left .more {
/* 因为棒棒糖的高度为35需要保持统一 */
height: 35px;
display: none;
}
.link-list {
display: flex;
justify-content: flex-end;
align-items: center;
}
.link-list .link {
margin: 0 20px;
cursor: pointer;
color: #666;
transition: color 0.2s;
border-bottom: 3px solid rgba(0, 0, 0, 0);
}
.link-list .link:hover {
color: #000;
}
.link-list .link-chosen {
border-bottom: 3px solid #e03ebf;
}
.header-divider {
height: 1px;
width: 100%;
background-color: #eee;
}
.main-container-block {
height: 80px;
width: 100%;
transition: height 0.2s;
/* background-color: #fff; */
}
@media screen and (max-width: 800px) {
.header-container {
padding: 15px 0;
}
.main-container-block {
height: 65px;
}
.header-container {
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
}
.header-left {
width: 100%;
display: flex;
justify-content: space-between;
}
.header-left .more {
display: flex;
align-content: center;
flex-wrap: wrap;
margin-right: 50px;
cursor: pointer;
}
.header-right-hidden {
display: none;
}
.header-right {
/* width: 100%; */
margin-top: 15px;
}
.link-list {
display: flex;
flex-direction: column;
margin: 20px 10px;
}
.link-list .link {
font-size: 23px;
margin-top: 10px;
}
}
</style>