要求就这么多,可以先看下效果如何:
重点:使用uniapp的scroll-view组件,如果是小程序原生开发也是这个组件;其次如果是html开发,就自己实现一个溢出滚动。
废话不多说,上代码:
data(){return{scrollTop:0,//tab标题的滚动条位置oldScrollTop:0,//tab标题的滚动条旧位置current:0,//预设当前项的值menuHeight:0,//左边菜单的高度menuItemHeight:0,//左边菜单item的高度itemId:'',//栏目右边scroll-view用于滚动的idtabbar:JSON.parse(uni.getStorageSync('categroy')),//渲染的数据,放在最后供你们测试arr:[],//储存距离顶部高度的数组scrollRightTop:0,//右边栏目scroll-view的滚动条高度timer:null//定时器}}CSS代码:
分别获取左侧和右侧每一个类别的高度
/***获取一个目标元素的高度*@elClass元素的类名*@dataVal储存高度的对象*/methods:{getElRect(elClass,dataVal){newPromise((resolve,reject)=>{constquery=uni.createSelectorQuery().in(this);query.select('.'+elClass).fields({size:true},res=>{//如果节点尚未生成,res值为null,循环调用执行if(!res){setTimeout(()=>{this.getElRect(elClass);},10);return;}this[dataVal]=res.height;resolve();}).exec();})}}计算右侧每个分类距离顶部的高度并保存
onReady(){this.getMenuItemTop()},mehods:{/***获取右边菜单每个item到顶部的距离*储存到arr数组里面用于后面滚动判断*/getMenuItemTop(){newPromise(resolve=>{letselectorQuery=uni.createSelectorQuery();selectorQuery.selectAll('.class-item').boundingClientRect((rects)=>{//如果节点尚未生成,rects值为[](因为用selectAll,所以返回的是数组),循环调用执行if(!rects.length){setTimeout(()=>{this.getMenuItemTop();},10);return;}rects.forEach((rect)=>{//视情况而定,这里减去rects[0].top,是因为第一项顶部可能不是贴到导航栏(比如有个搜索框的情况)//this.arr.push(rect.top-rects[0].top);this.arr.push(rect.top)resolve();})}).exec()})},}监听右侧元素滚动时交互的状态
methods:{/***观测元素相交状态*检测右边scroll-view的id为itemxx的元素与right-box的相交状态*如果跟.right-box底部相交,就动态设置左边栏目的活动状态*/asyncobserver(){this.tabbar.map((val,index)=>{letobserver=uni.createIntersectionObserver(this);observer.relativeTo('.right-box',{top:0}).observe('#item'+index,res=>{if(res.intersectionRatio>0){letid=res.id.substring(4);this.leftMenuStatus(id);}})})},/***设置左边菜单的滚动状态*@index传入的ID*/asyncleftMenuStatus(index){this.current=index;//如果为0,意味着尚未初始化if(this.menuHeight==0||this.menuItemHeight==0){awaitthis.getElRect('menu-scroll-view','menuHeight');awaitthis.getElRect('u-tab-item','menuItemHeight');}//将菜单活动item垂直居中this.scrollTop=index*this.menuItemHeight+this.menuItemHeight/2-this.menuHeight/2;}}实现左侧菜单点击联动右侧滚动
methods:{/***点击左边的栏目切换*@index传入的ID*/asyncswichMenu(index){if(this.arr.length==0){awaitthis.getMenuItemTop();}if(index==this.current)return;this.scrollRightTop=this.oldScrollTop;this.$nextTick(function(){this.scrollRightTop=this.arr[index];this.current=index;this.leftMenuStatus(index);})},}实现右侧菜单滚动联动左侧高亮
methods:{/***右边菜单滚动*如果不存在height2,意味着数据循环已经到了最后一个,设置左边菜单为最后一项即可*/asyncrightScroll(e){this.oldScrollTop=e.detail.scrollTop;if(this.arr.length==0){awaitthis.getMenuItemTop();}if(this.timer)return;if(!this.menuHeight){awaitthis.getElRect('menu-scroll-view','menuHeight');}setTimeout(()=>{//节流this.timer=null;//scrollHeight为右边菜单垂直中点位置//letscrollHeight=e.detail.scrollTop+this.menuHeight/2;//scrollHeight为右边菜单头部位置letscrollHeight=e.detail.scrollTop+20;for(leti=0;i