• 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>
              <!-- 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样式

    <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

    页面分为左右两个部分,

     先实现左右两边滚动效果,我们需要在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
  • 相关阅读:
    章节1:SQL语言简易入门
    章节0:MySQl学前知识储备
    iOS 设置导航栏全透明
    IOS修改Navigation Bar上的返回按钮文本颜色,箭头颜色以及导航栏按钮的颜色
    iOS import导入时没有提示的解决办法
    iOSAPP开发项目搭建
    如何搭建iOS项目基本框架
    UIWebView中JS与OC交互 WebViewJavascriptBridge的使用
    iOS概念之KVO(Key-Value Observing)
    oc调javascript方法(evaluateJavaScript:)&&js给oc发通知
  • 原文地址:https://www.cnblogs.com/zhoulifeng/p/9646296.html
Copyright © 2020-2023  润新知