究极干货,完美实现微信小程序商品左右联动scroll-view的实现及性能优化,点击左边,右边滚动;右边滚动,左边也对应变化
究极干货,完美实现微信小程序商品左右联动scroll-view的实现及性能优化,点击左边,右边滚动;右边滚动,左边也对应变化
微信小程序左右联动,点击左边右边滚动,滑动右边左边滚动及改变状态
微信小程序左右联动,点击左边右边滚动,滑动右边左边滚动及改变状态
如上图,在小程序中,我们经常需要一个功能,就是点击左边的列表选项,右边对应的内容滚动,而滑动右边的内容,左边对应的改变状态及位置,特别是商城站基本都涉及到,那么我们该怎么实现呢,这里我们就需要用到小程序的scroll-view这个组件;
先看代码
第一步,点击左边右边会对应滚动:
这个比较简单,利用scroll-view的属性scroll-into-view="",当我们点击左侧列表子项时,就把子项的id赋值给croll-into-view,就可以实现点击左侧,右侧滚动了,
第二步,滑动右侧,左侧高亮且滚动到可见区域:
这个才是左右联动的核心所在:那该怎么实现呢,思路是:scroll-view 有监听事件bindscroll,我们在监听事件里监听右侧内容滚动的高度,进而判断当前是属于那一块区域。在bindscroll事件里我们可以直接得到scrollTop当前滚动的高度,但是我怎么判断这个高度输入第几类商品呢,这个就需要得到右侧每一类商品的高度,然而每一类商品的高度不是写死的,由数据渲染的,有的数据多一点,高度就多一点,那该怎么获取呢,这个就需要我们用到小程序的另一个api wx.createSelectorQuery(),
获取右侧商品分类的高度代码:
var that=this;
var h=0;
var heightArr=[];
wx.createSelectorQuery().selectAll(’.sc_right_item’).boundingClientRect(function (rect) {//selectAll会选择所要含有该类名的盒子
}).exec(function (res) {
res[0].forEach((item)=>{
h+=item.height;
heightArr.push(h);
})
that.setData({heightArr:heightArr})
});
这样我们就得到右侧商品的分类的高度了,如上面获得的高度heightArr是一个数组,heightArr[0]就是第一类商品的高度(我这里是菜品1的高度),而heightArr[1]就是第二类商品的高度加上第一类商品的高度,以此类推;这里获取的高度单位为px;正好和scrollTop的单位也是px;所以我们不需要在rpx和px之间进行换算;
然后右边滑动,左边对应高亮及滚动代码:
上面代码我们何以看到:左侧的active状态通过cp_index=i来实现,而左侧滚动的位置由leftTop=i*左侧子项的高度来实现(左侧子项的高度用wx.createSelectorQuery()来获取,不能是写死的,因为scroll-top="{{leftTop}}" 的值是px,所有需要获取,不然用写死的rpx,就要每个手机都要进行换算)
性能优化代码:
想想看,我们右边每滑动一下,Scroll-view 的监听就执行了好多下(比如次数为n),在加上每次执行的过程中又执行for循环(比如次数为m),那么我们每滑动一下就必须setData的次数=n*m;性能可想而知,肯定会卡顿,那么怎么避免了,我们只需要在特定范围内执行一次,比如在0-500的高度内执行一次,那么我们就得另加判断,如下
第一类商品: 一 开始,我设oneShow=true,当它执行一次的时候就赋值为false,所以在第一类商品高度区域内只执行一次,如果到达第二类以上,就让oneShow=true回来,这样回滚的时候它又能执行;
第二类商品以上: 初始值zindex=0;如果不等于当前i值就让它执行,然后让它=i;第二次及而二次以上就不再执行,当它=i+1时又执行一次,然后在这个阶段就不再执行,以此类推
源码如下:
wxml:
<view class="containner">
<view class="top">左右联动例子</view>
<view class="cont">
<scroll-view scroll-y="true" class="scr_left" scroll-top="{{leftTop}}" scroll-with-animation="true">
<block wx:for="{{leftData}}" wx:for-item="lcai" wx:key="index">
<view class="sc_left_item {{cp_index==index? 'active':''}}" data-id="c_{{lcai.id}}" data-index="{{index}}" bindtap="leftTap" >
{{lcai.name}}
</view>
</block>
</scroll-view>
<scroll-view scroll-y="true" class="scr_right" scroll-into-view="{{currentScrollId}}" scroll-with-animation="true" bindscroll="bindscroll">
<block wx:for="{{rightData}}" wx:for-item="rcai" wx:key="index">
<view class="sc_right_item" id="c_{{rcai.id}}" data-id="c_{{rcai.id}}" data-index="{{index}}" bindtap="rightTap" >
<text>{{rcai.name}}</text>
<view class="images_wrap">
<image wx:for="{{rcai.img}}" wx:key="index" src="{{item}}"></image>
</view>
</view>
</block>
</scroll-view>
</view>
</view>
wxss:
page{
width: 100%;
height: 100%;
}
.containner{
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
}
.top{
width: 100%;
height: 50rpx;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #dbdbdb;
}
.cont{
display: flex;
justify-content: space-between;
width: 100%;
height: 100%;
}
.scr_left{
border-right: 1px solid #999;
width: 100rpx;
height: 100%;
box-sizing: border-box;
}
.scr_right{
width:500rpx;
height: 100%;
}
.sc_left_item{
width: 100rpx;
height: 200rpx;
display: flex;
align-items: center;
justify-content: center;
color: #333;
border-bottom: 2px solid #dbdbdb;
}
.sc_right_item{
margin-bottom: 30rpx;
}
.images_wrap{
width: 100%;
display: flex;
flex-wrap: wrap;
}
.sc_right_item image{width: 50%;display: block}
.active{
color: red;
border-bottom: 2px solid red;
}
js:
//index.js
//获取应用实例
const app = getApp()
Page({
data: {
currentScrollId:'',
cp_index:0,
leftTop:0,
left_item_height:0,
leftData:[
{
name:'菜品1',
id:'cp1'
},
{
name: '菜品2',
id: 'cp2'
},
{
name: '菜品3',
id: 'cp3'
},
{
name: '菜品4',
id: 'cp4'
},
{
name: '菜品5',
id: 'cp5'
},
{
name: '菜品6',
id: 'cp6'
},
{
name: '菜品7',
id: 'cp7'
},
{
name: '菜品8',
id: 'cp8'
},
{
name: '菜品9',
id: 'cp9'
},
{
name: '菜品10',
id: 'cp10'
},
{
name: '菜品11',
id: 'cp11'
},
{
name: '菜品12',
id: 'cp12'
}
],
rightData: [
{
name: '菜品1',
id: 'cp1',
img:[
'../../image/cp.jpg',
]
},
{
name: '菜品2',
id: 'cp2',
img: [
'../../image/cp.jpg',
'../../image/cp.jpg',
]
},
{
name: '菜品3',
id: 'cp3',
img: [
'../../image/cp.jpg',
'../../image/cp.jpg',
]
},
{
name: '菜品4',
id: 'cp4',
img: [
'../../image/cp.jpg',
'../../image/cp.jpg',
'../../image/cp.jpg',
'../../image/cp.jpg'
]
},
{
name: '菜品5',
id: 'cp5',
img: [
'../../image/cp.jpg',
'../../image/cp.jpg',
'../../image/cp.jpg'
]
},
{
name: '菜品6',
id: 'cp6',
img: [
'../../image/cp.jpg',
'../../image/cp.jpg',
'../../image/cp.jpg',
'../../image/cp.jpg',
'../../image/cp.jpg'
]
},
{
name: '菜品7',
id: 'cp7',
img: [
'../../image/cp.jpg',
'../../image/cp.jpg'
]
},
{
name: '菜品8',
id: 'cp8',
img: [
'../../image/cp.jpg',
'../../image/cp.jpg',
'../../image/cp.jpg',
'../../image/cp.jpg'
]
},
{
name: '菜品9',
id: 'cp9',
img: [
'../../image/cp.jpg',
'../../image/cp.jpg',
'../../image/cp.jpg'
]
},
{
name: '菜品10',
id: 'cp10',
img: [
'../../image/cp.jpg',
'../../image/cp.jpg',
'../../image/cp.jpg',
'../../image/cp.jpg'
]
},
{
name: '菜品11',
id: 'cp11',
img: [
'../../image/cp.jpg',
'../../image/cp.jpg',
'../../image/cp.jpg',
'../../image/cp.jpg'
]
},
{
name: '菜品12',
id: 'cp12',
img: [
'../../image/cp.jpg',
'../../image/cp.jpg',
'../../image/cp.jpg',
'../../image/cp.jpg'
]
}
],
heightArr:0,
zindex:0,
oneShow:true
},
onLoad:function(){
},
onReady:function(){
var that=this;
var h=0;
var heightArr=[];
wx.createSelectorQuery().select('.sc_left_item').boundingClientRect(function (rect) { //select会选择第一个类目的盒子
}).exec(function (res) {
that.setData({ left_item_height: res[0].height })
});
wx.createSelectorQuery().selectAll('.sc_right_item').boundingClientRect(function (rect) {//selectAll会选择所要含有该类名的盒子
}).exec(function (res) {
res[0].forEach((item)=>{
h+=item.height;
heightArr.push(h);
})
that.setData({heightArr:heightArr})
})
},
leftTap:function(e){
var index=e.currentTarget.dataset.index;
var id = e.currentTarget.dataset.id;
this.setData({ cp_index: index, currentScrollId:id})
},
bindscroll:function(e){
var zindex = this.data.zindex;
var oneShow=this.data.oneShow;
let scrollTop = e.detail.scrollTop;
let scrollArr = this.data.heightArr;
for (let i = 0; i < scrollArr.length; i++) {
if (scrollTop >= 0 && scrollTop < scrollArr[0]) {
if (oneShow){
console.log('==============aaa' + scrollTop + "==" + scrollArr[0]);
this.setData({
cp_index: 0,
leftTop: 0,
zindex:0,
oneShow:false
})
return
}
} else if (scrollTop >= (scrollArr[i - 1]) && scrollTop < scrollArr[i]) {
if (i != zindex){
console.log('==============bbb' + i + scrollTop + "==" + scrollArr[i]);
this.setData({
oneShow: true,
zindex:i,
cp_index: i,
leftTop: i * this.data.left_item_height
})
}
}
}
}
})
源码,也可以直接打开链接在打开小程序开发工具即可查看:https://developers.weixin.qq.com/s/t7uVgOmT7gae
————————————————
版权声明:本文为CSDN博主「疯!不会停息-春哥」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42120767/article/details/100030269