究極干貨,完美實(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