vue2.0和better-scroll实现左右联动效果

vue2.0和better-scroll实现左右联动效果

在做移动端商城或者其他页面的时候,经常会遇到左右联动的效果 vue2.0和better-scroll这个插件一起实现左右联动效果。

实现上面的效果,思路一定很重要,还有需求

  1. 左边一级分类和右边二级分类形成联动

  2. 当滑动右侧分类列表时, 更新左侧分类选中

  3. 点击左侧一级分类项时, 右侧列表滑动到对应位置

在vue脚手架的时候,引入第三方插件better-scroll,如果想了解的话,可以去看看它的中午文档说明,

npm install better-scroll --save直接安装到自己项目当中,并引入

1.页面结构搭建

<div class="search">
    
    <SearchNav>SearchNav>
    <div class="shop">
      
      <div class="menu-wrapper">
        <ul>
          
          <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样式


页面分为左右两个部分

vue2.0和better-scroll实现左右联动效果_第1张图片
先实现左右两边滚动效果,我们需要在methods定义一个方法,但是better-scroll的初始化一定要在数据渲染完成后进行

1
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标签的高度计算出来
vue2.0和better-scroll实现左右联动效果_第2张图片

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>
          
          <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>


<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>

你可能感兴趣的:(vue2.0和better-scroll实现左右联动效果)