在Vue中使用better-scroll横向滑动失效的问题

2,365 阅读2分钟

最近在学习一个Vue-H5的仿外卖的移动端项目。其中,很多滚动场景,包括滚动列表、轮播图等是用Better-Scroll插件实现的。具体使用方法参考better-scroll中文文档。使用过程中遇到问题:横向滑动不起作用,下面针对这个问题进行阐述。

better-scroll 滚动原理

在分析问题之前,我们有必要先介绍一下better-scroll的滚动原理,这里借用原作者的图,如下。

原理图

如图示,绿色部分为wrapper,也就是父容器,他的高度时固定的。黄色部分是content,这个是父容器的第一个子元素,它的高度会随着里面的内容大小而撑高。因此,只有当content的高度大于wrapper的高度时,我们才可以滚动内容区。

横向滑动问题

项目源码

<template>
  <div class="shop-info">
    <div class="info-content">
      <section class="section">
        <h3 class="section-title">商家实景</h3>
        <div class="pic-wrapper">
          <ul ref="picsUl" class="pic-list" >
            <li
              v-for="(pic, index) in info.pics"
              :key="index"
              class="pic-item">
              <img v-lazy="pic" width="120" height="90">
            </li>
          </ul>
        </div>
      </section>
    </div>
  </div>
</template>

<script>
import BScroll from 'better-scroll'
import { mapState } from 'vuex'
export default {
  computed: {
    ...mapState(['info'])
  },

  watch: {
    info() { // 刷新流程--> 更新数据
      this.$nextTick(() => {
        this._initScroll()
      })
    }
  },

  mounted() {
    // 如果this.info.pics数据还没有, 直接结束
    if (!this.info.pics) {
      return
    }

    // this.info.pics有数据了, 可以创建BScroll对象形成滑动
    this._initScroll()
  },

  methods: {
    _initScroll() {
      new BScroll('.pic-wrapper', {
        scrollX: true // 水平滑动
      })
    }
  }
}
</script>

<style lang="stylus" rel="stylesheet/stylus">
  @import "../../../common/stylus/mixins.styl"

  .shop-info
    position absolute
    top 195px
    bottom 0
    left 0
    width 100%
    background #fff
    overflow hidden
    .section
      padding 16px 14px 14px
      font-size 16px
      background-color #fff
      color #666
      border-bottom 1px solid #eee
      position relative
      .section-title
        color #000
        font-weight 700
        line-height 16px
        > .iconfont
          float right
          color #ccc
      .pic-wrapper
        width: 100%
        overflow: hidden
        white-space: nowrap
        margin-top 16px
        .pic-list
          font-size: 0
          .pic-item
            display: inline-block
            margin-right: 6px
            width: 120px
            height: 90px
            &:last-child
              margin: 0
</style>

问题分析

analyse1

分析Element元素可以看出,元素ul的宽度并没有被里面的几个li元素的宽度撑开。所以在初始化 better-scroll时,ul的宽度并没有大于ul的父元素pic-wrapper的宽度,因此better-scroll并不生效。

解决方法

从上面的分析可以得出,我们只要在初始化 better-scroll之前,将元素ul的宽度设置为元素li再加上其margin的值即可。

methods: {
    _initScroll() {
      // 动态计算ul的宽度
      const ul = this.$refs.picsUl
      const liWidth = 120 // li width : 120px
      const space = 6 // margin-right: 6px
      const count = this.info.pics.length
      ul.style.width = (liWidth + space) * count - space + 'px'

      new BScroll('.pic-wrapper', {
        scrollX: true // 水平滑动
      })
    }
  }

analyse2

这样就解决了横向滑动的问题,我们再看一下Element相应的元素。ul的宽度有了,并且大于其父元素的宽度,当我们横向滑动时,ul样式中的transform也在变化。

总结

使用better-scroll时,我们要先弄明白其滚动的原理,然后需要分析使用的时机。一般我们是在页面加载之后或者数据更新之后再去初始化 better-scroll。在Vue中,数据是异步更新的,可以在this.$nextTick回调中初始化 better-scroll 。

还需要注意的是,有时候,我们需要在new BScroll()之前,手动的设置content的宽度或者高度。

参考文献

  1. better-scroll中文文档
  2. 当 better-scroll 遇见 Vue
  3. BetterScroll:可能是目前最好用的移动端滚动插件