scroll-view左右聯(lián)動(dòng)

究極干貨,完美實(shí)現(xiàn)微信小程序商品左右聯(lián)動(dòng)scroll-view的實(shí)現(xiàn)及性能優(yōu)化,點(diǎn)擊左邊,右邊滾動(dòng);右邊滾動(dòng),左邊也對(duì)應(yīng)變化

究極干貨,完美實(shí)現(xiàn)微信小程序商品左右聯(lián)動(dòng)scroll-view的實(shí)現(xiàn)及性能優(yōu)化,點(diǎn)擊左邊,右邊滾動(dòng);右邊滾動(dòng),左邊也對(duì)應(yīng)變化

微信小程序左右聯(lián)動(dòng),點(diǎn)擊左邊右邊滾動(dòng),滑動(dòng)右邊左邊滾動(dòng)及改變狀態(tài)

微信小程序左右聯(lián)動(dòng),點(diǎn)擊左邊右邊滾動(dòng),滑動(dòng)右邊左邊滾動(dòng)及改變狀態(tài)

如上圖,在小程序中,我們經(jīng)常需要一個(gè)功能,就是點(diǎn)擊左邊的列表選項(xiàng),右邊對(duì)應(yīng)的內(nèi)容滾動(dòng),而滑動(dòng)右邊的內(nèi)容,左邊對(duì)應(yīng)的改變狀態(tài)及位置,特別是商城站基本都涉及到,那么我們?cè)撛趺磳?shí)現(xiàn)呢,這里我們就需要用到小程序的scroll-view這個(gè)組件;

先看代碼


第一步,點(diǎn)擊左邊右邊會(huì)對(duì)應(yīng)滾動(dòng):

這個(gè)比較簡(jiǎn)單,利用scroll-view的屬性scroll-into-view="",當(dāng)我們點(diǎn)擊左側(cè)列表子項(xiàng)時(shí),就把子項(xiàng)的id賦值給croll-into-view,就可以實(shí)現(xiàn)點(diǎn)擊左側(cè),右側(cè)滾動(dòng)了,

第二步,滑動(dòng)右側(cè),左側(cè)高亮且滾動(dòng)到可見區(qū)域:

這個(gè)才是左右聯(lián)動(dòng)的核心所在:那該怎么實(shí)現(xiàn)呢,思路是:scroll-view 有監(jiān)聽事件bindscroll,我們?cè)诒O(jiān)聽事件里監(jiān)聽右側(cè)內(nèi)容滾動(dòng)的高度,進(jìn)而判斷當(dāng)前是屬于那一塊區(qū)域。在bindscroll事件里我們可以直接得到scrollTop當(dāng)前滾動(dòng)的高度,但是我怎么判斷這個(gè)高度輸入第幾類商品呢,這個(gè)就需要得到右側(cè)每一類商品的高度,然而每一類商品的高度不是寫死的,由數(shù)據(jù)渲染的,有的數(shù)據(jù)多一點(diǎn),高度就多一點(diǎn),那該怎么獲取呢,這個(gè)就需要我們用到小程序的另一個(gè)api wx.createSelectorQuery(),

獲取右側(cè)商品分類的高度代碼:

var that=this;

var h=0;

var heightArr=[];

wx.createSelectorQuery().selectAll(’.sc_right_item’).boundingClientRect(function (rect) {//selectAll會(huì)選擇所要含有該類名的盒子

}).exec(function (res) {

res[0].forEach((item)=>{

h+=item.height;

heightArr.push(h);

})

that.setData({heightArr:heightArr})

});

這樣我們就得到右側(cè)商品的分類的高度了,如上面獲得的高度heightArr是一個(gè)數(shù)組,heightArr[0]就是第一類商品的高度(我這里是菜品1的高度),而heightArr[1]就是第二類商品的高度加上第一類商品的高度,以此類推;這里獲取的高度單位為px;正好和scrollTop的單位也是px;所以我們不需要在rpx和px之間進(jìn)行換算;

然后右邊滑動(dòng),左邊對(duì)應(yīng)高亮及滾動(dòng)代碼:



上面代碼我們何以看到:左側(cè)的active狀態(tài)通過cp_index=i來實(shí)現(xiàn),而左側(cè)滾動(dòng)的位置由leftTop=i*左側(cè)子項(xiàng)的高度來實(shí)現(xiàn)(左側(cè)子項(xiàng)的高度用wx.createSelectorQuery()來獲取,不能是寫死的,因?yàn)閟croll-top="{{leftTop}}" 的值是px,所有需要獲取,不然用寫死的rpx,就要每個(gè)手機(jī)都要進(jìn)行換算)

性能優(yōu)化代碼:

想想看,我們右邊每滑動(dòng)一下,Scroll-view 的監(jiān)聽就執(zhí)行了好多下(比如次數(shù)為n),在加上每次執(zhí)行的過程中又執(zhí)行for循環(huán)(比如次數(shù)為m),那么我們每滑動(dòng)一下就必須setData的次數(shù)=n*m;性能可想而知,肯定會(huì)卡頓,那么怎么避免了,我們只需要在特定范圍內(nèi)執(zhí)行一次,比如在0-500的高度內(nèi)執(zhí)行一次,那么我們就得另加判斷,如下


第一類商品: 一 開始,我設(shè)oneShow=true,當(dāng)它執(zhí)行一次的時(shí)候就賦值為false,所以在第一類商品高度區(qū)域內(nèi)只執(zhí)行一次,如果到達(dá)第二類以上,就讓oneShow=true回來,這樣回滾的時(shí)候它又能執(zhí)行;

第二類商品以上: 初始值z(mì)index=0;如果不等于當(dāng)前i值就讓它執(zhí)行,然后讓它=i;第二次及而二次以上就不再執(zhí)行,當(dāng)它=i+1時(shí)又執(zhí)行一次,然后在這個(gè)階段就不再執(zhí)行,以此類推


源碼如下:

wxml:

<view class="containner">

? <view class="top">左右聯(lián)動(dòng)例子</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

//獲取應(yīng)用實(shí)例

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會(huì)選擇第一個(gè)類目的盒子

? ? }).exec(function (res) {

? ? ? that.setData({ left_item_height: res[0].height })


? ? });

? ? wx.createSelectorQuery().selectAll('.sc_right_item').boundingClientRect(function (rect) {//selectAll會(huì)選擇所要含有該類名的盒子

? ? }).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

? ? ? ? ? })


? ? ? ? }

? ? }

? ? ? }

? }

})


源碼,也可以直接打開鏈接在打開小程序開發(fā)工具即可查看:https://developers.weixin.qq.com/s/t7uVgOmT7gae

————————————————

版權(quán)聲明:本文為CSDN博主「瘋!不會(huì)停息-春哥」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。

原文鏈接:https://blog.csdn.net/weixin_42120767/article/details/100030269

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容