微信小程序---scroll-view實現左右兩側聯調


1.靜態效果圖如下:

 

 

 

 

2.代碼如下:

(1)在menu.wxml中:

<!--pages/menu/menu.wxml-->
<!-- 輪播圖 使用組件 -->
<banner imgHeight="{{imgHeight}}" backgroundArr="{{backgroundArr}}" />

<view class="main">
  <!-- 左側 -->
    <scroll-view  scroll-y="true" class="left"   scroll-into-view="left{{leftId}}">
        <view id="left{{item.id}}" bindtap="changeFn" data-id="{{index}}" class="scroll-view-item {{current===index?'active':''}}" 
       wx:for
="{{menuArr}}" wx:key="*this">{{item.title}}
     </view> </scroll-view> <!-- 右側 --> <!-- 要點擊左側時,右側實現滑動到指定位置,要加scroll-with-animation="true 才能實現過度滾動動畫效果--> <scroll-view scroll-y="true" bindscroll="bindscrollFn" class="right" scroll-into-view="right{{rightId}}" scroll-with-animation="true"
   showScrollbar
="{{showScrollbar}}" enhanced="{{enhanced}}" > <!-- scroll-into-view="right{{rightId}}" 要與 下面這個view的id一致 --> <view id="right{{item.id}}" class="scroll-view-item box" wx:for="{{menuArr}}" wx:key="*this"> <!-- 標題 --> <view class="title">{{item.title}}</view> <view class="content"> <view wx:for="{{item.subArr}}" wx:key="*this" wx:for-item="subItem"> <image src="{{subItem.imgSrc}}" mode="widthFix"></image> <text>{{subItem.imgDesc}}</text> </view> </view> </view> </scroll-view> </view>

(2)在menu.wxss中:

/* pages/menu/menu.wxss */
.main{
  width: 100%;
  height: calc(100vh - 361.11rpx); /*使用rpx單位 避免其他其他機型底部內容被覆蓋問題*/
  background-color: #efefef;
  display: flex;
  justify-content: space-between;
  overflow: hidden;
}
.main .left{
  width: 25%;
  height: 100%;
  background-color: #fff;
  border-right: 1px solid #ccc;
  box-sizing: border-box;
}
.left .scroll-view-item{
  width: 100%;
  height: 100rpx;
  line-height: 100rpx;
  text-align: center;
  border-bottom: 2rpx solid #ccc;
  font-size: 28rpx;
  position: relative;
}
.left .scroll-view-item.active{
  background-color: #efefef;
}
.left .scroll-view-item.active::before{
  display: block;
}
.left .scroll-view-item::before{
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 8rpx;
  height: 100%;
  background-color: #333399;
  display: none;
}
.right{
  width: 75%;
  height: 100%;
  padding:0 4%;
  box-sizing: border-box;
}
.right .title{
  width: 100%;
  height: 80rpx;
  line-height:80rpx;
  font-weight: bold;
}
.right .content{
  margin-bottom: 20rpx;
  padding: 20rpx 14rpx 0 0;
  border-radius: 10rpx;
  /* width: 100%; */
  background-color: #fff;
  display: flex;
  justify-content: flex-start;
  flex-wrap: wrap;
  box-sizing: border-box;
}
.right .content view{
  margin-bottom: 10rpx;
  width: 30%;
  margin-left: 3.2%;
}
.right .content view image{
  width: 100%;
  display: block;
  border-radius: 10rpx;
}
.right .content view text{
  display: block;
  height: 50rpx;
  line-height: 50rpx;
  text-align: center;
  font-size: 28rpx;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

(3)在menu.js中:

// pages/menu/menu.js
Page({
  data: {
    showScrollbar: false,
    enhanced: true,
    current: 0,
    leftId: 0,
    rightId: 0,
    rightArr: [],
    menuArr:[],
    // 控制menu頁面的輪播圖高度 為520
    imgHeight: 520,
    // 輪播圖數據
    backgroundArr: [
      "/images/banner/menubanner1.jpg",
      "/images/banner/menubanner2.jpg",
      "/images/banner/menubanner3.jpg"
    ],
  },

  //左側點擊事件 獲取每一項上的自定義屬性值,給到current 每次點擊 對active類名進行添加加或刪除
  changeFn(e) {
    // console.log(e.currentTarget.dataset.id);
    let index = e.currentTarget.dataset.id;
    this.setData({
      current: index, //修改data中的值
      leftId: index,
      rightId: index
    })
  },
  // 右側滾動事件
  bindscrollFn(e) {
    let st = e.detail.scrollTop; //獲取右側內容滾動的高度
    let tempArr = this.data.rightArr; //獲取data中的rightArr數組
    // console.log(tempArr);
    for(let i=0;i<tempArr.length;i++){
      // 每個box都有高度,st在第index個box和(index+1)之間的話,當前就是index
      // 減去10像素,是因為當點擊左側第二項的時候,第二項頭部還有第一項底部的空間,此時會閃跳選中第一項,而第二項沒被選中
      if(st>=tempArr[i]-10 && st<tempArr[i+1]-10){
        // 將數組的索引給到左側滾動的id
        this.setData({
          current: i,
          leftId: i,
        })
        return; //當當前項符合條件的時候,結束本次循環,避免符合條件時還在一直循環,導致頁面卡頓
      }
    }
  },

  // 相當於 vue 生命周期 mounted
  getBoxH(){
    let _this = this; //存儲this,避免this指向被修改報錯

    // 使用定時器的原因:因為數組在遍歷的時候是有延遲的,onReady掛載完成了,但是數組還在渲染, 
    // query.exec搶在頁面數組渲染完成前,拿到盒子的高度導致數據不准確,
    // 使用定時器就是為了等到頁面數組的數據渲染完成在獲取盒子的高度,這時拿到的數據是比較准確的
    setTimeout(() => {
      const query = wx.createSelectorQuery()
      query.selectAll('.box').boundingClientRect()  //獲取所有box盒子的高度 .box是類名
      query.selectViewport().scrollOffset()
      let heightArr = [0];//定義一個第0項值為0的數組,用於存儲所有盒子的高度
      let baseNum = 0;
      query.exec(function (res) {
        // console.log(res[0]);
        // 遍歷res[0],獲取其中每一項的height值
        res[0].map(val => {
          //因為比較的高度是當前項高度與當前項高和下一項值高度的和,所以要累加之后再存儲到heightArr
          baseNum +=val.height;
          heightArr.push(baseNum)
        })
        // console.log(heightArr);
        // 將heightArr數組數據存儲到rightArr中 ,在其他地方使用
        _this.setData({
          rightArr:heightArr
        })
      })
    }, 500)
  },
  // 在onShow生命周期中請求數據
  onShow(){
    // 使用雲函數請求數據
    let _this = this;
    wx.cloud.callFunction({
      name:"getMenuData"
    }).then(res=>{
      // console.log(res.result.data[0].arr);
        _this.setData({
          menuArr:res.result.data[0].arr
        })
        // 調用方法, 在請求到數據之后在獲取高度,保證獲取到的高度是正確的
        this.getBoxH();
    })
  }
})
//這樣還存在一個問題:
// 就是在點擊左側倒數第一項時,會閃跳到第二項,主要是因為左側倒數第二項對應的右側區塊高度在右側
// 倒數第一和倒數第二項區塊高度和之間,因此選中了倒數第二項

// onShow(){} 和 onLoad(){}生命周期的區別
// onShow 當小程序切換到后台后被隱藏,再次進入小程序會在執行一次,如果要每次進入該頁面時要請求數據可以在這個生命周期中
// onLoad 是頁面只加載一次,切換到后台在切換回來不會再請求數據

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM