描述
基于vue的移动端菜单,菜单可以横向滚动和展开,支持点击居中选择导航
效果
页面
<div class="main-top">
<div class="main-block">
<div class="flex-row">
<div class="flex-cell" v-for="(item, index) in state.categoryDataList" :key="item.id">
<a
href="#"
:class="state.categoryid == item.id ? 'active' : ''"
@click.prevent="handleClickMenu(item.id, index)"
>
<img :src="item.imgUrl" />
<span>{{ item.categoryName }}</span>
</a>
</div>
</div>
</div>
<div class="main-block-all" @click.prevent="showPopup()">
<span>全部</span>
<img src="@/assets/images/min-icon19.png" alt="" />
</div>
</div>
<van-popup v-model:show="show" round position="top" :overlay-style="overlayHeight">
<div class="main-popup">
<div class="popup">
<div class="popup-content">
<h5>全部分类</h5>
<div class="main-block">
<div class="main-flex-row">
<div
class="main-flex-cell"
v-for="(item, i) in state.categoryDataList"
:key="item.id"
>
<a
href="#"
:class="state.categoryid == item.id ? 'active' : ''"
@click.prevent="handleClickMenu(item.id, i)"
>
<img :src="item.imgUrl" />
<span>{{ item.categoryName }}</span>
</a>
</div>
</div>
</div>
<p @click="showUnPopup()"><span>点击收起</span></p>
</div>
</div>
</div>
</van-popup>
逻辑
const handleClickMenu = (id: string, index?: number) => {
state.categoryid = id;
chooseNav(id, index);
};
function chooseNav(id: string, index?: number) {
// 当前点击元素的左边距离
const distanceL = document
.getElementsByClassName('flex-cell')
[index].getBoundingClientRect().left;
// 点击元素的一半宽度
const elementHW = document.getElementsByClassName('flex-cell')[index].clientWidth / 2;
// 屏幕宽度
const screenW = document.body.clientWidth;
// 屏幕宽度的一半
const screenHW = document.body.clientWidth / 2;
// 元素右边距离
const distanceR = screenW - distanceL;
// 获取最外层的元素
const scrollBox = document.getElementsByClassName('flex-row');
// 滚动条滚动的距离
const scrollL = scrollBox[0].scrollLeft;
// 当元素左边距离大于屏幕一半宽度 或者 右边距离大于屏幕一半距离的时候
if (distanceL > screenHW - elementHW || distanceR > screenHW - elementHW) {
// 滚动条最终的滚动距离
scrollBox[0].scrollLeft = scrollL + (distanceL - screenHW + elementHW);
}
}
样式
<style scoped lang="less">
.flex-row::-webkit-scrollbar {
display: none; /* Chrome Safari */
}
.flex-row {
padding-right: 0.4rem;
display: flex;
overflow-x: auto;
/* 隐藏滚动条 */
scrollbar-width: none; /* firefox */
-ms-overflow-style: none; /* IE 10+ */
justify-content: space-between;
a {
width: 100%;
display: inline-block;
}
.flex-cell {
text-align: center;
flex-grow: 0;
flex-shrink: 0;
width: calc(20vw - 0.125rem);
a.active > img {
border-color: #40ae36;
}
a.active > span {
color: #40ae36;
}
a > span {
width: 100%;
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
a > img {
margin: 0 auto;
width: 0.8rem;
height: 0.8rem;
padding: 0.02rem;
border-radius: 50rem;
box-sizing: border-box;
border: 0.02rem solid #fff;
}
}
}
:deep(.popup-content) {
.main-flex-row {
display: flex;
flex-wrap: wrap;
// justify-content: space-between;
padding: 0 0.3rem;
margin: 0.5rem 0 0.25rem 0;
a {
width: 100%;
display: inline-block;
}
.main-flex-cell {
text-align: center;
width: calc(20vw - 0.125rem);
a.active > img {
border-color: #40ae36;
}
a.active > span {
color: #40ae36;
}
a > span {
width: 100%;
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
a > img {
margin: 0 auto;
width: 0.8rem;
height: 0.8rem;
padding: 0.02rem;
border-radius: 50rem;
box-sizing: border-box;
border: 0.02rem solid #fff;
}
}
}
}
</style>