vue2.0和better-scroll實現左右聯動效果

在作移動端商城或者其餘頁面的時候,常常會遇到左右聯動的效果,今天小編vue2.0和better-scroll這個插件一塊兒實現左右聯動效果。css

實現上面的效果,思路必定很重要,還有需求html

1. 左邊一級分類和右邊二級分類造成聯動vue

2. 當滑動右側分類列表時, 更新左側分類選中vuex

3. 點擊左側一級分類項時, 右側列表滑動到對應位置npm

在vue腳手架的時候,引入第三方插件better-scroll,若是想了解的話,能夠去看看它的中午文檔說明,數組

npm install better-scroll --save直接安裝到本身項目當中,並引入app

 

1.頁面結構搭建ide

<div class="search">
    <!-- 搜索導航 -->
    <SearchNav></SearchNav>
    <div class="shop">
      <!-- 左邊 -->
      <div class="menu-wrapper">
        <ul>
          <!-- current -->
          <li 
            class="menu-item"
            v-for="(goods,index) in searchgoods" 
            :key="index"
            :class="{current: index === currentIndex}"
            @click="clickList(index)"
            ref="menuList"
            >
            <span>{{goods.name}}</span>
          </li>
        </ul>
      </div>
      <!-- 右邊 -->
      <div class="shop-wrapper">
        <ul ref="itemList">
          <li class="shops-li" v-for="(goods, index1) in searchgoods" :key="index1">
            <div class="shops-title">
              <h4>{{goods.name}}</h4>
              <a href="">查看更多 > </a>
            </div>
            <ul class="phone-type" v-if="goods.tag === 'phone'">
              <li v-for="(phone,index) in goods.category" :key="index">
                <img :src="phone.icon" alt="">
              </li>
            </ul>
            <ul class="shops-items">
              <li v-for="(item, index2) in goods.items" :key="index2">
                <img :src="item.icon" alt="">
                <span>{{item.title}}</span>
              </li>
            </ul>
          </li>
        </ul>
      </div>
    </div>
  </div> 

css樣式flex

<style lang="stylus" rel="stylesheet/stylus" scoped>
  @import "../../common/stylus/mixins.styl"
  .search
    width 100%
    height 100%
    background-color #f5f5f5
    overflow hidden
    .shop 
      display flex
      position absolute
      top 60px
      bottom 50px
      width 100%
      overflow hidden
      .menu-wrapper
        background-color #e0e0e0
        width 80px
        flex 0 0 80px
        .menu-item 
          width 100%
          height 60px
          background #fafafa
          display flex
          justify-content center
          align-items center
          font-family lighter
          color #666
          position relative
        .current
          color #e02e24
          background #ffffff
        .current::before 
          content ''
          background-color #e02e24
          width 4px
          height 30px
          position absolute
          left 0
      .shop-wrapper
        flex 1
        background #fff
        .shops-title
          display flex
          flex-direction row
          padding 0 10px
          height 40px
          align-items center
          justify-content space-between
          color #9999
        a
          text-decoration none
          color #9c9c9c
          font-size 14px
        .shops-items
          display flex 
          flex-wrap wrap
          li
            display flex
            flex-direction column
            width 33.3%
            height 90px
            justify-content center
            align-items center 
            img 
              width 60%
              height 60%
              margin-bottom 5px
            span
              color #151516
              font-size 13px
        .phone-type
          width 100%
          display flex
          flex-direction row
          flex-wrap wrap
          border-bottom-1px (#cccccc)
          li
            width 33.3%
            display flex 
            justify-content center
            align-items center 
            margin 5px 0
            img
              width 70%
</style>  
View Code

 

頁面分爲左右兩個部分,this

 

 先實現左右兩邊滾動效果,咱們須要在methods定義一個方法,可是better-scroll的初始化必定要在數據渲染完成後進行

methods:{
    _initBScroll(){
    //左邊滾動
      this.leftBscroll = new BScroll('.menu-wrapper',{});
      //右邊滾動
      this.rightBscroll = new BScroll('.shop-wrapper',{
      probeType:3   //在滾動中觸發scroll 事件
    });  
   }
}

 咱們經過watch監聽searchgoods數據是否有,並經過this.$nextTick去調用_initBScroll方法。

 searchgoods是數據存儲的地方

watch:{
    searchgoods(){
      //監聽數據
      this.$nextTick(() =>{
        //左右兩邊滾動
        this. _initBScroll();
      //右邊列表高度
      this._initRightHeight()
      })
    }
  },

2.計算出每個li標籤的高度,並把它存放在一個數組當中

1.須要在data中定義兩個變量

data () {
    return {
      scrollY:0, //右側列表滑動的y軸座標
      rightLiTops:[] //全部分類頭部位置
    }
  },

2.在methods中定義一個方法,_initRightHeight,這個方法是用於計算每一個li標籤的高度

 //求出右邊列表的高度
    _initRightHeight(){
      let itemArray=[]; //定義一個僞數組
      let top = 0;
      itemArray.push(top)
      //獲取右邊全部li的禮
      let allList = this.$refs.itemList.getElementsByClassName('shops-li');
      //allList僞數組轉化成真數組
      Array.prototype.slice.call(allList).forEach(li => {
        top += li.clientHeight; //獲取全部li的每個高度
        itemArray.push(top)
      });
      this.rightLiTops = itemArray;
      // console.log(this.rightLiTops)
    },

經過上面的方法,已經把全部li標籤的高度計算出來

 

3.監聽右邊滾動事件

 經過better-scroll提供的 on 事件,當右邊內容滾動的時候計算出滾動的距離,必定要在滾動的時候觸發這個事件_initBScroll這個方法當中去寫

//監聽右邊滾動事件
      this.rightBscroll.on('scroll',(pos) => {
        this.scrollY = Math.abs(pos.y);
        console.log(this.scrollY)
      })

4.動態綁定class樣式

1須要給左右的li標籤綁定一個:class="{current: index === currentIndex}",經過計算屬性,實現這個效果
computed: {
    //動態綁定class類名
    currentIndex(index) {
      const {scrollY,rightLiTops} = this;
      return rightLiTops.findIndex((tops,index )=>{
        this._initLeftScroll(index);  //調用左右聯調滾動效果
        return scrollY >= tops && scrollY < rightLiTops[index + 1]
      })
    }
  },

 5.點擊左邊實現滾動和左右滾動聯調

5.1實現點擊左邊實現滾動效果,須要給左邊的li標籤綁定一個點擊事件@click="clickList(index)",經過index來來計算出點擊的位置

this.rightLiTops[index]經過index索引獲得點擊的時候,會獲得每一塊li標籤的高度
經過better-scroll提供的
scrollTo來實現具體滾動的位置
clickList(index){
        this.scrollY = this.rightLiTops[index];
        this.rightBscroll.scrollTo(0,-this.scrollY,200,)
    },

5.2當右邊內容滾動的時候,滾動必定的程度的時候,但願左邊也會隨着滾動,

5.2.1經過ref全部全部li標籤

let menu = this.$refs.menuList;
5.2.2獲得他們每個索引值
let el = menu[index];
5.2.3經過scrollToElement實現滾動目標元素位置
//左右聯調 
    _initLeftScroll(index){
      let menu = this.$refs.menuList;
      let el = menu[index];
      this.leftBscroll.scrollToElement(el,300,0,-300)
    }

 以上都是基本上完成了這些需求了

最終代碼

<template>
  <div class="search">
    <!-- 搜索導航 -->
    <SearchNav></SearchNav>
    <div class="shop">
      <!-- 左邊 -->
      <div class="menu-wrapper">
        <ul>
          <!-- current -->
          <li 
            class="menu-item"
            v-for="(goods,index) in searchgoods" 
            :key="index"
            :class="{current: index === currentIndex}"
            @click="clickList(index)"
            ref="menuList"
            >
            <span>{{goods.name}}</span>
          </li>
        </ul>
      </div>
      <!-- 右邊 -->
      <div class="shop-wrapper">
        <ul ref="itemList">
          <li class="shops-li" v-for="(goods, index1) in searchgoods" :key="index1">
            <div class="shops-title">
              <h4>{{goods.name}}</h4>
              <a href="">查看更多 > </a>
            </div>
            <ul class="phone-type" v-if="goods.tag === 'phone'">
              <li v-for="(phone,index) in goods.category" :key="index">
                <img :src="phone.icon" alt="">
              </li>
            </ul>
            <ul class="shops-items">
              <li v-for="(item, index2) in goods.items" :key="index2">
                <img :src="item.icon" alt="">
                <span>{{item.title}}</span>
              </li>
            </ul>
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>

<script>
import SearchNav from './Children/SearchNav'
import {mapState} from 'vuex'
import BScroll from 'better-scroll'
export default {
  name: 'chat',
  data () {
    return {
      scrollY: 0, //右側列表滑動的y軸座標
      rightLiTops:[] //全部分類頭部位置
    }
  },
  computed: {
    ...mapState(['searchgoods']),   //列表數據
    //動態綁定class類名
    currentIndex(index) {
      const {scrollY,rightLiTops} = this;
      return rightLiTops.findIndex((tops,index )=>{
        this._initLeftScroll(index);
        return scrollY >= tops && scrollY < rightLiTops[index + 1]
      })
    }
  },
  mounted() {
    this.$store.dispatch('reqSearchGoods')
  },
  components: {
    SearchNav
  },
  watch:{
    searchgoods(){
      //監聽數據
      this.$nextTick(() =>{
        //左右兩邊滾動
        this. _initBScroll();
        //右邊列表高度
        this._initRightHeight()
      })
    }
  },
  methods:{
    _initBScroll() {
      //左邊滾動
      this.leftBscroll = new BScroll('.menu-wrapper',{});
    
      //右邊滾動
      this.rightBscroll = new BScroll('.shop-wrapper',{
        probeType:3
      });
      //監聽右邊滾動事件
      this.rightBscroll.on('scroll',(pos) => {
        this.scrollY = Math.abs(pos.y);
        // console.log(this.scrollY)
      })
    },
    
    //求出右邊列表的高度
    _initRightHeight(){
      let itemArray=[]; //定義一個僞數組
      let top = 0;
      itemArray.push(top)
      //獲取右邊全部li的禮
      let allList = this.$refs.itemList.getElementsByClassName('shops-li');
      //allList僞數組轉化成真數組
      Array.prototype.slice.call(allList).forEach(li => {
        top += li.clientHeight; //獲取全部li的每個高度
        itemArray.push(top)
      });
      this.rightLiTops = itemArray;
      // console.log(this.rightLiTops)
    },
    //點擊左邊實現滾動
    clickList(index){
        this.scrollY = this.rightLiTops[index];
        console.log(this.scrollY)
        this.rightBscroll.scrollTo(0,-this.scrollY,200,)
    },
    //左右聯調 
    _initLeftScroll(index){
      let menu = this.$refs.menuList;
      let el = menu[index];
      this.leftBscroll.scrollToElement(el,300,0,-300)
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="stylus" rel="stylesheet/stylus" scoped>
  @import "../../common/stylus/mixins.styl"
  .search
    width 100%
    height 100%
    background-color #f5f5f5
    overflow hidden
    .shop 
      display flex
      position absolute
      top 60px
      bottom 50px
      width 100%
      overflow hidden
      .menu-wrapper
        background-color #e0e0e0
        width 80px
        flex 0 0 80px
        .menu-item 
          width 100%
          height 60px
          background #fafafa
          display flex
          justify-content center
          align-items center
          font-family lighter
          color #666
          position relative
        .current
          color #e02e24
          background #ffffff
        .current::before 
          content ''
          background-color #e02e24
          width 4px
          height 30px
          position absolute
          left 0
      .shop-wrapper
        flex 1
        background #fff
        .shops-title
          display flex
          flex-direction row
          padding 0 10px
          height 40px
          align-items center
          justify-content space-between
          color #9999
        a
          text-decoration none
          color #9c9c9c
          font-size 14px
        .shops-items
          display flex 
          flex-wrap wrap
          li
            display flex
            flex-direction column
            width 33.3%
            height 90px
            justify-content center
            align-items center 
            img 
              width 60%
              height 60%
              margin-bottom 5px
            span
              color #151516
              font-size 13px
        .phone-type
          width 100%
          display flex
          flex-direction row
          flex-wrap wrap
          border-bottom-1px (#cccccc)
          li
            width 33.3%
            display flex 
            justify-content center
            align-items center 
            margin 5px 0
            img
              width 70%
</style>  
View Code
相關文章
相關標籤/搜索