本文由 Loui 原创,如需转载,请先私信或评论。
背景
腾讯课堂 PC 端网页顶部导航条有这样一个多级下拉菜单,鼠标悬浮上去可以一级级地查看课程分类,效果非常好,想用 Nuxt3 仿照做一个。
直接使用 antdv 里的 Dropdown 组件也可以实现类似的效果,如下所示:
直接用这个组件和腾讯课堂的效果还是有一些不同,也不太好展示具体的课程分类。所以还是决定自己做一个,下面是最终效果和实现步骤,供大家参考、批评。
最终效果
我这里使用的是 Nuxt3 ,其实具体实现的代码和使用 Vue3 去做是差不多的,简单改一下就能在 Vue3 项目中使用,和框架并没有很大关系。
实现步骤
第一步:准备三个响应式变量
vue
<script setup lang="ts">
const isFirstOpened = ref(false)
const isSecondOpened = ref(false)
const secondId = ref(-1) // secondId 默认是 -1
</script>
第二步:准备页面结构和样式
vue
<template>
// 最大的div,使用相对定位,之后出现的弹框都放到它里面,并设置成绝对定位
<div
class="box"
@mouseenter="isFirstOpened = true"
@mouseleave="isFirstOpened = false"
>
课程分类
// 这里我使用的是 Nuxt 里的 Icon 模块:https://nuxt.com/modules/icon
// 你需要在项目中额外下载引入才能使用
<Icon
name="icon-park:up"
class="icon"
:class="{ rotate: isFirstOpened }"
/>
// 一级弹框,只有一个,里面是很多个 .first-item
// 根据 isFirstOpened 决定是否显示
// 如果鼠标移入了它,那就让 isSecondOpened 变成 true
// 如果鼠标移出了它,那就让 isSecondOpened 变成 false,secondId 恢复成原始值 -1
<div
v-show="isFirstOpened"
class="first"
@mouseenter="() => { isSecondOpened = true }"
@mouseleave="() => { isSecondOpened = false; secondId = -1 }"
>
// 循环产生 7 个 .first-item
// 由于暂时没有准备数据,所以就直接简单地循环7次,你可以根据需要改成遍历后台传过来的数据
// 如果鼠标移入了一个 item,那就让 secondId 变成相应的序号
<div
v-for="i in 7"
:key="i"
class="first-item"
@mouseenter="() => { secondId = i }"
>
<NuxtLink>
IT·互联网
</NuxtLink>
// 二级弹框,每个 .first-item 里都有一个
// 根据 isSecondOpened 和 secondId 决定是否显示
// 里面的内容就是相应分类下细分分类
<div
v-show="isSecondOpened && secondId === i"
class="second"
>
<div
v-for="ii in 7"
:key="ii"
class="line"
>
<NuxtLink class="left">
前沿技术{{ secondId }}
</NuxtLink>
<div class="right">
<NuxtLink
v-for="iii in 6"
:key="iii"
class="right-item"
to="/"
>
人工智能{{ secondId }}
</NuxtLink>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.box {
position: relative;
display: flex;
align-items: center;
height: 68px;
font-size: 14px;
color: #3e454d;
cursor: pointer;
// 给下拉图标加了一点动画效果,和腾讯课堂保持一致
.icon {
margin-left: 2px;
font-size: 16px;
transition: all 0.3s ease-in-out;
transform: rotate(-180deg);
&.rotate {
transform: rotate(0);
}
}
.first {
position: absolute;
top: 80%;
left: 50%;
width: 83px;
padding: 6px;
background-color: #fff;
border-radius: 10px;
box-shadow: rgb(0 80 179 / 12%) 0 8px 30px;
transform: translateX(-50%);
.first-item {
display: block;
padding: 13px 0;
font-weight: bolder;
color: #2b2c30;
text-align: center;
border-radius: 9px;
transition: all 0.1s ease-in-out;
&:hover {
background-color: $primary-bg;
}
.second {
position: absolute;
top: 0;
left: 100%;
// 二级弹框需要设置最小高度,和腾讯课堂保持一致
min-height: 316px;
padding: 10px 20px;
background-color: #fff;
border-radius: 12px;
box-shadow: rgb(0 80 179 / 12%) 0 8px 30px;
.line {
display: flex;
align-items: flex-start;
width: 498px;
padding: 10px 0;
font-size: 12px;
transition: all 0.1s ease-in-out;
.left {
min-width: 80px;
text-align: left;
&:hover {
color: $primary;
}
}
.right {
display: flex;
flex-wrap: wrap;
gap: 10px;
.right-item {
font-weight: normal;
color: #667280;
text-decoration: none;
&:hover {
color: $primary;
}
}
}
}
}
}
}
}
</style>
总结
在这个下拉菜单中,我们通过控制响应式变量的值来显示和隐藏不同的部分。这套代码其实还有很多可以完善的地方,如果你有其他更好的实现方法或者思路,欢迎在评论区补充。如果你发现了什么 Bug 或者有其它问题,也欢迎在评论区提出来。
如果这篇文章有帮到你,还请点一个不要钱的赞,感谢支持 ❤️