0%

Better-Scroll在手机端横向滚动的应用

今天上班写页面的时候,遇到有个需求是做一个可以横向滑动的菜单,类似于小程序里面的scroll-view组件。当然,如果只是简单的使用overflow-y:scroll去实现横向滑动菜单的话,体验不怎么好,因为在左右滑动的时候,总会有一种卡顿不流畅的感觉,为了改善这种状况,我决定引入一个滴滴前端团队的某位成员开源的滚动插件:better-scroll,不过这个插件使用比较多的场景还是在竖直方向的下拉列表里面,但今天我借助它来制作横向滑动的菜单,两种场景在使用上其实差不多,区别仅仅是横向滚动的场景中需要我们手动计算一下所有item的宽度之和,然后把总宽度赋值给它们的父容器,先看看最终的效果:

实现起来也不复杂,我把主要的代码贴出来,感兴趣的同学可以自己去尝试:

imgSearch.vue

    <template>
      <div class="imgSearch_container">
        <div class="top_nav">
          <Header title="图搜" />
          <div class="search_nav">
              <img class="search_img" src="../../assets/mock_imgs/goodsImg.png" />
              <div class="categorys" ref="categorys">
                  <div class="categoty_list" ref="categoty_list">
                        <span 
                          class="category_item" 
                          ref="category_item"
                          :class="selectedCategoryIndex === index ? 'selected':''" 
                          v-for="(item, index) in categorys" 
                          @click="handleCategorySelect(index)"
                          :key="index">{{item.text}}</span>
                  </div>
              </div>
          </div>
        </div>
      </div>
    </template>
    
    <script>
    import BScroll from 'better-scroll'
    import Header from '../../components/header/header.vue'
    
    export default {
        name: 'ImageSearch',
        data() {
          return {
            categorys: [
              { id: 0, text: '全部' },
              { id: 1, text: '外套' },
              { id: 2, text: '裙子' },
              { id: 3, text: '衬衫' },
              { id: 4, text: '鞋子' },
              { id: 5, text: '牛仔裤' },
              { id: 6, text: '毛衣' },
            ],
            // ...
            selectedCategoryIndex: 0
          }
        },
        components: {
          Header
        },
        methods: {
          // ...
          handleCategorySelect (index) {
              this.selectedCategoryIndex = index
          }
        },
        mounted () {
          let width = 0
          for (let  i = 0; i < this.categorys.length + 1; i++) {
              width += this.$refs.category_item[0].getBoundingClientRect().width
          }
          this.$refs.categoty_list.style.width = width / parseFloat(document.documentElement.style.fontSize) + 'rem'
    
          if (!this.scroll) {
            this.scroll = new BScroll(this.$refs.categorys, {
              scrollX: true,
              scrollY: false,
              momentum: false,
              snap: {
                loop: this.loop,
                threshold: 0.3,
                speed: 400
              },
              click: true
            })
          } else {
            this.scroll.refresh()
          }
        }
    }
    </script>
    
    <style lang="less" scoped>
    @import './imageSearch.less';
    </style>
    

imageSearch.less

    .imgSearch_container {
        .top_nav {
            position: relative;
            z-index: 100;
            background: #fff;
        }
    
        .search_nav {
            display: flex;
            height: 107px;
            border-top: 1px solid #E5E5E5;
            border-bottom: 1px solid #E5E5E5;
            .search_img {
                width: 110px;
                height: 110px;
            }
            .categorys {
                width: 640px;
                overflow: hidden;
    
                .categoty_list {
                    display: flex;
                    width: 100%;
                    height: 128px;
                }
    
                .category_item {
                    flex-shrink: 0;
                    width: 116px;
                    height: 46px;
                    line-height: 46px;
                    border-radius: 25px;
                    border: 2px solid #9C9C9C;
                    font-size: 24px;
                    color: #9C9C9C;
                    text-align: center;
                    margin-top: 30px;
                    margin-left: 18px;
    
                    &.selected {
                        border-color: #F96388;
                        color: #F96388;
                    }
                }
            }
        }
    }