vue仿餓了麼app中vue和better-scroll實現列表左右聯動效果

一.實現思路

(1)實現上是左右分別一個better-scroll列表
(2)利用計算右側列表每一個大區塊的高度來計算左側的位置
  • 1
  • 2

二.實現

1.實現左右兩個better-scroll

(1)dom結構(better-scroll要求,會把最外層dom的第一個子元素作爲要滾動的區域)

左邊滾動列表dom
 <div class="menu-wrapper" v-el:menu-wrapper>
      <ul>
        <li v-for="item in goods" class="menu-item"
            :class="{'current':currentIndex === $index}"
            @click="selectMenu($index,$event)">
          <span class="text border-1px">
            <span v-show="item.type > 0" class="icon"
              :class="classMap[item.type]"></span>{{item.name}}
          </span>
        </li>
      </ul>
    </div>

右邊滾動列表dom
<div class="food-wrapper" v-el:food-wrapper>
      <ul>
        <li v-for="item in goods" class="food-list food-list-hook">
          <h1 class="title">{{item.name}}</h1>
          <ul>
            <li v-for="food in item.foods" class="food-item border-1px">
              <div class="icon">
                <img width="57" height="57" :src="food.icon">
              </div>
              <div class="content">
                <h2 class="name">{{food.name}}</h2>
                <p class="desc">{{food.description}}</p>
                <div class="extra">
                  <span class="count">月售{{food.sellCount}}</span>
                  <span>好評率{{food.rating}}%</span>
                  <div class="price">
                    <span class="now">¥{{food.price}}</span>
                    <span class="old" v-show="food.oldPrice">¥{{food.oldPrice}}</span>
                  </div>
                </div>
              </div>
            </li>
          </ul>
        </li>
      </ul>
    </div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

在數據請求完成後的$nextTick中初始化better-scroll,就能實現兩個列表分別能滾動,至於聯動,要後面自己做

_initScroll() {
        this.menuScroll = new BScroll(this.$els.menuWrapper,{
          click:true   //允許better-scroll列表上的點擊事件
        });
        this.foodsScroll = new BScroll(this.$els.foodWrapper,{
          probeType : 3   //讓better-scroll監聽scroll事件
        });
        this.foodsScroll.on('scroll',(pos) => {
          this.scrollY =Math.abs(Math.round(pos.y));
        })
      },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2.實現聯動效果

(1)具體的聯動實現思路

  • 在渲染完成後($nextTick內),初始化better-scroll,並在初始化函數內添加右側列表的scroll監聽事件,並記錄scrollY值到,存入vue的data中
  • 在渲染完成後($nextTick內),計算右側列表的每一個大區塊的高度,並累加,存入數組listHeight
  • 因爲scrollY值在滾動中總是不斷變化的,所以在computed中計算出currentIndex,當前滾動區域是哪一個大區塊,也就是listHeight數組的下標
  • 在dom中根據currentIndex應用左側列表被點中的樣式
  • 在左側列表某一項被點中的時候,右側列表滑動到某一個大塊區域,
//初始化better-scroll
_initScroll() {
        this.menuScroll = new BScroll(this.$els.menuWrapper,{
          click:true
        });
        this.foodsScroll = new BScroll(this.$els.foodWrapper,{
          probeType : 3
        });
        this.foodsScroll.on('scroll',(pos) => {
          this.scrollY =Math.abs(Math.round(pos.y));
        })
      },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
_calculateHeight() {
        let foodList = this.$els.foodWrapper.getElementsByClassName("food-list-hook");
        let height = 0;
        this.listHeight.push(height);
        for(let i=0;i<foodList.length;i++) {
          let item = foodList[i];
          height += item.clientHeight;
          this.listHeight.push(height);
        }
      }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
computed: {
      currentIndex() {
        for(let i=0;i< this.listHeight.length;i++) {
          let height1 = this.listHeight[i];
          let height2 = this.listHeight[i+1];
          if(!height2 || (this.scrollY >= height1 && this.scrollY < height2)){
            return i;
          }
        }
        return 0;
      }
    },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
<div class="menu-wrapper" v-el:menu-wrapper>
      <ul>
        <!--  :class="{'current':currentIndex === $index}" 就是根據currentIndex應用左側列表被點中的樣式 -->
        <li v-for="item in goods" class="menu-item"
            :class="{'current':currentIndex === $index}"
            @click="selectMenu($index,$event)">
          <span class="text border-1px">
            <span v-show="item.type > 0" class="icon"
              :class="classMap[item.type]"></span>{{item.name}}
          </span>
        </li>
      </ul>
    </div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
//被點擊事件
//dom
<div class="menu-wrapper" v-el:menu-wrapper>
      <ul>
        <!-- @click="selectMenu($index,$event)" 就是點擊事件 -->
        <li v-for="item in goods" class="menu-item"
            :class="{'current':currentIndex === $index}"
            @click="selectMenu($index,$event)">
          <span class="text border-1px">
            <span v-show="item.type > 0" class="icon"
              :class="classMap[item.type]"></span>{{item.name}}
          </span>
        </li>
      </ul>
    </div>
//js    
selectMenu(index,event) {
        if(!event._constructed) {
          return ;
        }
        let foodList = this.$els.foodWrapper.getElementsByClassName("food-list-hook");
        let el = foodList[index];
        this.foodsScroll.scrollToElement(el,300);
      },
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章