微信小程序?qū)崿F(xiàn)左右聯(lián)動的菜單列表

實現(xiàn)效果如下:


效果展示.gif

實現(xiàn)左右聯(lián)動的菜單列表吧黄,主要依靠scroll-view的是三個屬性:
scroll-top:設(shè)置豎向滾動條位置(可視區(qū)域最頂部到scroll-view頂部的距離)氧骤;
scroll-into-view:值應(yīng)為某子元素id(id不能以數(shù)字開頭)陌选。設(shè)置哪個方向可滾動救氯,則在哪個方向滾動到該元素驾诈;
bindscroll:滾動時觸發(fā)凤瘦,event.detail = {scrollLeft, scrollTop, scrollHeight, scrollWidth, deltaX, deltaY}

結(jié)構(gòu)圖示:


布局.png

wxml:

<!-- tabs -->
<view class='tabs font28 color9'>
  <view class='tab-item {{currentTab==0?"tab-active":""}}' bindtap='changeTab' data-pos='0'>選擇項目</view>
  <view class='tab-item {{currentTab==1?"tab-active":""}}' bindtap='changeTab' data-pos='1'>選擇技師</view>
  <view class='tab-item {{currentTab==2?"tab-active":""}}' bindtap='changeTab' data-pos='2'>優(yōu)惠券</view>
</view>

<!-- 選擇項目 -->
<view wx:if="{{currentTab==0}}" class='cont-pro'>
  <!-- 左側(cè)列表 -->
  <view class='pro-left font28 color9'>
    <view wx:for="{{serviceTypes}}" class='pro-title {{index==currentLeft?"font30 color3 bgWhite":""}}' bindtap='proItemTap' data-pos='{{index}}'>{{item.type}}</view>
  </view>
  <!-- 右側(cè)列表 -->
  <scroll-view class='pro-right' scroll-y scroll-with-animation="true" scroll-into-view="{{selectId}}" bindscroll="scrollEvent" scroll-top="{{scrollTop}}">
    <!-- id要用來實現(xiàn)點擊左側(cè)右側(cè)滾動至相應(yīng)位置的效果冤竹;class(pro-box)要用來計算右側(cè)對應(yīng)左側(cè)某一分類的高度 -->
    <!-- id: item0, item1, item2... (注意:不能直接使用數(shù)字或漢字做id)-->
    <view id='{{"item"+index}}' class='pro-box' wx:for="{{serviceTypes}}" wx:for-index="index" wx:for-item="item">
      <!-- 右側(cè)列表里的標(biāo)題拂封,高度為50px -->
      <view class="item-title font30">{{item.type}}</view>
      <view class='pro-item' wx:for="{{item.services}}" wx:for-index="idx" wx:for-item="itemName">
        <image class='pro-img' src='{{itemName.img}}'></image>
        <view class='pro-text'>
          <view class='item-name color3 font32'>{{itemName.name}}</view>
          <view class='pro-tag'>
            <text wx:for="{{itemName.label}}" wx:for-item="tag">{{tag}}</text>
          </view>
          <view class='pro-bottom'>
            <text style='color:#C93131;' class='font32'>¥{{itemName.price}}</text>
            <view class='count font30 color6'>
              <text catchtap='subCount' data-pos='{{idx}}' data-index='{{index}}' data-sid='{{itemName.id}}'>-</text>
              <text class='color3'>{{itemName.count?itemName.count:0}}</text>
              <text catchtap='addCount' data-pos='{{idx}}' data-index='{{index}}' data-sid='{{itemName.id}}'>+</text>
            </view>
          </view>
        </view>
      </view>
    </view>
  </scroll-view>
</view>

<!-- 選擇技師 -->
<view wx:if="{{currentTab==1}}" class='staff'>
  ...
</view>

<!-- 優(yōu)惠券-->
<view wx:if="{{currentTab==2}}" class='coupon'>
  ...
</view>

js:

var app = getApp();
Page({
  //右側(cè)分類的高度累加數(shù)組
  //比如:[洗車數(shù)組的高度,洗車+汽車美容的高度鹦蠕,洗車+汽車美容+精品的高度冒签,...]
  heightArr: [],
  //記錄scroll-view滾動過程中距離頂部的高度
  distance: 0,

  /**
   * 頁面的初始數(shù)據(jù)
   */
  data: {
    currentTab: 0,  //選擇項目、選擇技師钟病、優(yōu)惠券
    currentLeft: 0, //左側(cè)選中的下標(biāo)
    selectId: "item0",  //當(dāng)前顯示的元素id
    scrollTop: 0, //到頂部的距離
    serviceTypes: [], //項目列表數(shù)據(jù)
    staffList: [],
    coupons: []
  },

  /**
   * 生命周期函數(shù)--監(jiān)聽頁面加載
   */
  onLoad: function(options) {
    this.request();
  },

  //請求列表數(shù)據(jù)
  request() {
    app.HttpClient.request({url: "services"}).then((res) => {
      console.log(res);
      this.setData({
        serviceTypes: res.data.serviceTypes,
        staffList: res.data.staffList,
        coupons: res.data.coupons
      });
      this.selectHeight();
    })
  },

  //選擇項目左側(cè)點擊事件 currentLeft:控制左側(cè)選中樣式  selectId:設(shè)置右側(cè)應(yīng)顯示在頂部的id
  proItemTap(e) {
    this.setData({
      currentLeft: e.currentTarget.dataset.pos,
      selectId: "item" + e.currentTarget.dataset.pos
    })
  },

  //計算右側(cè)每一個分類的高度萧恕,在數(shù)據(jù)請求成功后請求即可
  selectHeight() {
    let that = this;
    this.heightArr = [];
    let h = 0;
    const query = wx.createSelectorQuery();
    query.selectAll('.pro-box').boundingClientRect()
    query.exec(function(res) {
      res[0].forEach((item) => {
        h += item.height;
        that.heightArr.push(h);
      })
      console.log(that.heightArr);
      // [160, 320, 1140, 1300, 1570, 1840, 2000]
      // 160:洗車標(biāo)題高度50px,item的高度110肠阱,洗車只有一個item票唆,所以50+110*1=160px;
      // 320: 汽車美容標(biāo)題高度50px,只有一個item屹徘,再加上洗車的高度走趋,所以50+110*1+160=320px;
      // ...
    })
  },

  //監(jiān)聽scroll-view的滾動事件
  scrollEvent(event) {
    if (this.heightArr.length == 0) {
      return;
    }
    let scrollTop = event.detail.scrollTop;
    let current = this.data.currentLeft;
    if (scrollTop >= this.distance) { //頁面向上滑動
      //如果右側(cè)當(dāng)前可視區(qū)域最底部到頂部的距離 超過 當(dāng)前列表選中項距頂部的高度(且沒有下標(biāo)越界),則更新左側(cè)選中項
      if (current + 1 < this.heightArr.length && scrollTop >= this.heightArr[current]) {
        this.setData({
          currentLeft: current + 1
        })
      }
    } else { //頁面向下滑動
      //如果右側(cè)當(dāng)前可視區(qū)域最頂部到頂部的距離 小于 當(dāng)前列表選中的項距頂部的高度噪伊,則更新左側(cè)選中項
      if (current - 1 >= 0 && scrollTop < this.heightArr[current - 1]) {
        this.setData({
          currentLeft: current - 1
        })
      }
    }
    //更新到頂部的距離
    this.distance = scrollTop;
  }
})

數(shù)據(jù)結(jié)構(gòu):


數(shù)據(jù)結(jié)構(gòu).png

如果你還想實現(xiàn)從其他頁面簿煌,點擊按鈕跳轉(zhuǎn)到當(dāng)前頁面,并且列表滾動到指定項鉴吹,此項在可視區(qū)域的第一個展示:

  //優(yōu)惠券點擊事件
  couponTap(e) {
    let item = e.currentTarget.dataset.item;
    if (item.limitServiceName) {
      this.setData({
        currentTab: 0
      })
      this.scrollTo(item.limitServiceName);
    }
  },

  //滾動到指定名稱的某一項(通過列表的商品name來判斷姨伟,也可以用id或者其他的,只要是列表項的唯一標(biāo)志)
  scrollTo(name) {
    let that = this;
    const query = wx.createSelectorQuery()
    query.select(".pro-item").boundingClientRect()
    //計算每一個item的高度(右側(cè)分類的小標(biāo)題高度是在css里寫死的50px)
    query.exec(function(res) {
      that.moveHeight(res[0].height, name);
    })
  },

  moveHeight(height, name) {
    let list = this.data.serviceTypes;
    let top = 50; //右側(cè)每一分類的標(biāo)題名稱的高度為50px豆励,top記錄每一個標(biāo)題到頂部的距離
    for (let i = 0; i < list.length; i++) {
      for (let j = 0; j < list[i].services.length; j++) {
        //如果當(dāng)前的item是要滾動到頂部的夺荒,
        if (list[i].services[j].name == name) {
          this.setData({
            scrollTop: height * j + top
          })
          break;
        }
      }
      //右側(cè)每劃過一個分類,就把此分類的高度和標(biāo)題的高度累加到top上
      top = top + list[i].services.length * height + 50;
    }
  }
moveTo.gif

wxss:

.cont-pro {
  height: 100%;
  display: flex;
  background-color: #fff;
}

.pro-left {
  width: 160rpx;
  flex-basis: 160rpx;
  background-color: #f6f6f6;
  overflow-y: scroll;
}

.pro-title {
  width: 100%;
  height: 100rpx;
  line-height: 100rpx;
  text-align: center;
}

.pro-right {
  flex: 1;
  background-color: #fff;
  overflow-y: scroll;
}

.item-title {
  width: 100%;
  height: 50px;
  line-height: 100rpx;
  padding: 0 30rpx;
  box-sizing: border-box;
}

.item-name {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 1;
  overflow: hidden;
  word-break: break-all;
}

.pro-item {
  width: 100%;
  display: flex;
  padding: 30rpx;
  box-sizing: border-box;
}

.pro-img {
  width: 160rpx;
  height: 160rpx;
  flex-basis: 160rpx;
  flex-shrink: 0;
  border-radius: 4rpx;
  margin-right: 30rpx;
  background-color: #f5f5f5;
}

.pro-text {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.pro-tag {
  color: #f08d31;
  font-size: 22rpx;
}

.pro-tag text {
  padding: 4rpx 10rpx;
  background-color: rgba(240, 141, 49, 0.15);
  margin-right: 10rpx;
  border-radius: 2rpx;
}

.pro-bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.count {
  width: 170rpx;
  flex-basis: 170rpx;
  background-color: #f6f6f6;
  border-radius: 28rpx;
  display: flex;
}

.count text {
  flex: 1;
  text-align: center;
  line-height: 50rpx;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肆糕,一起剝皮案震驚了整個濱河市般堆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌诚啃,老刑警劉巖淮摔,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異始赎,居然都是意外死亡和橙,警方通過查閱死者的電腦和手機仔燕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來魔招,“玉大人晰搀,你說我怎么就攤上這事“彀撸” “怎么了外恕?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長乡翅。 經(jīng)常有香客問我鳞疲,道長,這世上最難降的妖魔是什么蠕蚜? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任尚洽,我火速辦了婚禮,結(jié)果婚禮上靶累,老公的妹妹穿的比我還像新娘腺毫。我一直安慰自己,他們只是感情好挣柬,可當(dāng)我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布潮酒。 她就那樣靜靜地躺著,像睡著了一般邪蛔。 火紅的嫁衣襯著肌膚如雪澈灼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天店溢,我揣著相機與錄音叁熔,去河邊找鬼。 笑死床牧,一個胖子當(dāng)著我的面吹牛荣回,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播戈咳,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼心软,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了著蛙?” 一聲冷哼從身側(cè)響起删铃,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎踏堡,沒想到半個月后猎唁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡顷蟆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年诫隅,在試婚紗的時候發(fā)現(xiàn)自己被綠了腐魂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡逐纬,死狀恐怖蛔屹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情豁生,我是刑警寧澤兔毒,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站甸箱,受9級特大地震影響眼刃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜摇肌,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望仪际。 院中可真熱鬧围小,春花似錦、人聲如沸树碱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽成榜。三九已至框舔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赎婚,已是汗流浹背刘绣。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留挣输,地道東北人纬凤。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像撩嚼,于是被迫代替她去往敵國和親停士。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,055評論 2 355

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