vue3+vant3 使用 van-sidebar 侧导航组件实现菜单左右联动效果
最编程
2024-03-30 16:49:45
...
先看一下效果图:
主要解决的问题是当菜单顶部有van-sticky粘性布局时,左右联动准确定位如何实现
页面结构:
<van-sticky>
<div class="menu_header">...省略,这部分高度固定约140px</div>
</van-sticky>
<!-- 菜单左右联动 -->
<div class="menu_detail" >
<!-- 左侧菜单 -->
<div class="menu_list">
<van-sidebar v-model="tabValue" >
<van-sidebar-item
:title="item.clsdesc"
v-for="(item,index) in menuList"
:key="index"
@click="handleMenulist(index)"/>
</van-sidebar>
</div>
<!-- 右侧菜单 -->
<div id="goodListId">
<div v-for="(item,index1) in menuList" :key="index1" :id="'scroll'+index1">
<!--商品卡片-->
<div class="coffee_card">
<span>{{item.clsdesc}}</span>
<van-card v-for="(coffee,index2) in item.detail" ...省略></van-card>
</div>
</div>
</div>
</div>
js部分:主要在于handleMenulist()及handleScroll()的实现
<script>
import { ref, reactive, toRefs, onMounted} from 'vue'
export default {
name: 'menu',
components: {
},
setup() {
const router = useRouter()
const tabValue = ref(0)
const state = reactive({
menuList: [],
})
onMounted(() => {
//...省略从后台接口获取menuList数据过程
// 监听滚动条位置
window.addEventListener('scroll', handleScroll, true)
})
//左侧菜单点击联动左侧
const handleMenulist=(index)=>{
tabValue.value = index
let navPage = document.querySelector('#scroll' + index)
//navPage.offsetTop需要减去165店铺头部所占高度,需<170否则菜单切换会回弹
document.querySelector("#goodListId").scrollTop = navPage.offsetTop-165
}
//右侧菜单联动左侧
const handleScroll=()=>{
//scrollTop从0开始增大,局限在#goodListId div内
let scrollTop = document.querySelector("#goodListId").scrollTop
for(let a = 0;a<state.menuList.length;a++){
//offsetTop获取每块scroll的距离屏幕最顶端的值
//本menuList中9组元素的offsetTop固定值介于[179,1879]
//故offsetTop-170(店铺头部高度约140,增30余量)得到距离#goodListId最顶端的高度
//循环比较当scrollTop一旦大于某scroll的offsetTop-170,则切换左侧菜单选中index
if(document.querySelector('#scroll' + a).offsetTop-170 < scrollTop ){
tabValue.value = a
}
}
}
return {
...toRefs(state),
tabValue,
handleMenulist,
}
}
}
</script>
css部分:
<style>
.menu_detail{
height: calc(100vh - 140px);
display:flex;
}
.menu_list{
width:auto;
height: 100%;
background-color: #FDF1EA;
}
#goodListId{
overflow: auto;
width: -webkit-fill-available;
}
/* 选中标签三角标识 */
.van-sidebar-item--select:before {
position: absolute;
top: 50%;
left: 0;
width: 0;
height: 0;
border-top: 5px solid transparent;
border-left: 10px solid #FF6900;
border-bottom: 5px solid transparent;
-webkit-transform: translateY(-50%);
background-color:#fff;
transform: translateY(-50%);
content: '';
}
</style>
一些知识点:
HTML精确定位:scrollLeft,scrollWidth,clientWidth,offsetWidth
- scrollHeight: 获取对象的滚动高度。
- scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离
- scrollTop:设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离
- scrollWidth:获取对象的滚动宽度
- offsetHeight:获取对象相对于版面或由父坐标 offsetParent 属性指定的父坐标的高度
- offsetLeft:获取对象相对于版面或由 offsetParent 属性指定的父坐标的计算左侧位置
- offsetTop:获取对象相对于版面或由 offsetTop 属性指定的父坐标的计算顶端位置
- event.clientX 相对文档的水平座标
- event.clientY 相对文档的垂直座标
- event.offsetX 相对容器的水平坐标
- event.offsetY 相对容器的垂直坐标
- document.documentElement.scrollTop 垂直方向滚动的值
- event.clientX+document.documentElement.scrollTop 相对文档的水平座标+垂直方向滚动的量
这里是javascript中建造迁移转变代码的常用属性
- 页可见区域宽: document.body.clientWidth;
- 网页可见区域高: document.body.clientHeight;
- 网页可见区域宽: document.body.offsetWidth (包含边线的宽);
- 网页可见区域高: document.body.offsetHeight (包含边线的宽);
- 网页正文全文宽: document.body.scrollWidth;
- 网页正文全文高: document.body.scrollHeight;
- 网页被卷去的高: document.body.scrollTop;
- 网页被卷去的左: document.body.scrollLeft;
- 网页正文项目组上: window.screenTop;
- 网页正文项目组左: window.screenLeft;
- 屏幕辨别率的高: window.screen.height;
- 屏幕辨别率的宽: window.screen.width;
- 屏幕可用工作区高度: window.screen.availHeight;