基于scroll-view横向滚动的类目表实战案例。
发布于 4 年前 作者 ccui 3795 次浏览 来自 分享

基于scroll-view横向滚动制作的类目表组件

在电商项目中经常用到的就是一些类别滚动条,例如在某多以及某宝中在首页非常常见。

上面顶部下面就采用了这种滚动条的效果。

原理:

首先获取scroll-view中内容的实际宽度,然后计算出scrollLeft的最大值,然后根据用户点击的位置,判断当前点击是在左边还是右边(我们以屏幕的中点为分割线,中点左侧为左边,中点右侧为右边),同时根据点击方向判断移动方向(点击左侧向右移动,点击右侧像左移动),然后我们获取被点后当前的scrollLeft值,然后获取被点击元素的宽度以及被点击元素的left值,计算出需要移动的距离,改变现有的scollLeft值。如果向右移动后的scollLeft值超过最大的scollLeft值,我们就取scrollLeft的最大值。如果向左移动scollLeft值小于0,我们就取零。

下面是组件的制作过程:

  1. 首先创建category-x的组件目录,然后生成组件文件。
  2. 相关代码

WXML代码:

		

  
      
      
        {{item}}
      
    
  


wxss代码:

/* components/category-x/category-x.wxss */

.catbar{
  width:100%
}

.categories{
  height:100%;
  white-space: nowrap;
  box-sizing: border-box;
  border-bottom2rpx solid #f6f6f6;
  -webkit-overflow-scrolling: touch;
}

.category {
  display: inline-block;
  box-sizing: border-box;
  height100%;
}

.category:first-child {
  padding-left20rpx;
}

.category-name{
  display: inline-block;
  box-sizing: border-box;
  width100%;
  height100%;
  font-size32rpx;
  line-height80rpx;
  color#353535;
}

.current-category {
  color#e64340;
  border-bottom6rpx solid #e64340;
}

JS代码:

// components/category-x/category-x.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    //category bar的高度,单位为rpx
    height: {
      typeNumber,
      value: 0
    },
    //设置横向滚动条位置
    scrollLeft: {
      typeNumber,
      value: 0
    },
    //数据
    categoriesData: {
      typeArray,
      value: []
    },
    //当前索引
    nowIndex: {
      typeNumber,
      value: 0
    },
    //元素间的间距
    paddingRight:{
      type:Number,
      value:32
    },
    //第一个元素的左间距
    firstPaddingLeft:{
      type:Number,
      value:20
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
  },
  lifetimes: {
    attached: function () {
      this._getSystemInfo();
      this._getContentWidth();
    }
  },
  /**
   * 组件的方法列表
   */
  methods: {
    //获取设备参数
    _getSystemInfo: function () {
      var _this = this;
      wx.getSystemInfo({
        success: (res) => {
          var pxTorpxRatio = 750 / res.screenWidth;
          _this.setData({
            pxTorpxRatio: pxTorpxRatio,
            windowWidth: res.screenWidth
          });
        }
      });
    },
    //获取内部总宽度,单位是px
    _getContentWidth: function () {
      var _this = this;
      _this._getCategoryInfo().then((res) => {
        var dataLength = _this.data.categoriesData.length;
        _this.setData({
          contentWidth: ((res.width * dataLength * _this.data.pxTorpxRatio) + dataLength * _this.data.paddingRight + _this.data.firstPaddingLeft) / _this.data.pxTorpxRatio
        });
      })
    },
    //改变点击
    onChanging: function (event{
      var tappedIndex = event.currentTarget.dataset.index;
      this.setData({
        nowIndex: tappedIndex
      });
      //获取点击元素的宽度以及left值
      var _this = this;
      _this._getCategoryInfo().then((res) => {
        _this.setData({
          tappedWidth: res.width,
          tappedLeft: res.left
        }, () => {
          _this._getCategoriesScrollLeft().then((res) => {
            _this.setData({
              scrollLeft: res.scrollLeft
            }, () => {
              _this._onMoving();
            });
          });
        });
      });
      this.triggerEvent("change",{current:tappedIndex},{})
    },
    //移动
    _onMoving: function () {
      var tappedLeft = this.data.tappedLeft;
      var tappedWidth = this.data.tappedWidth;
      var scrollLeft = this.data.scrollLeft;
      var windowWidth = this.data.windowWidth;
      var contentWidth = this.data.contentWidth;
      var maxScrollLeft = contentWidth - windowWidth;
      var tappedScrollLeft;
      if (tappedLeft > windowWidth / 2) {
        var moveDis = scrollLeft + (tappedLeft - ((windowWidth / 2) - tappedWidth));
        tappedScrollLeft = (moveDis > maxScrollLeft) ? maxScrollLeft : moveDis;
      } else {
        var moveDis = scrollLeft - (((windowWidth / 2) - tappedWidth) - tappedLeft);
        tappedScrollLeft = (moveDis < 0) ? 0 : moveDis;
      }
      this.setData({
        scrollLeft: tappedScrollLeft
      });
    },
    //获取当前元素的信息
    _getCategoryInfo: function () {
      var _this = this;
      return new Promise((resolve, reject) => {
        _this.createSelectorQuery().select(".current-category").boundingClientRect((res) => {
          resolve(res);
        }).exec();
      });
    },
    //获取scroll-view的scroll-left值
    _getCategoriesScrollLeft: function () {
      var _this = this;
      return new Promise((resolve, reject) => {
        _this.createSelectorQuery().select(".categories").fields({
          scrollOffset: true
        }, (res) => {
          resolve(res);
        }).exec();
      });
    }
  }
})

Tip:

  1. 在page.json中引入组件后,height值为必填,categories-data为必填值。其余为不强制。默认值通过观察js中的properties可以看出。
  2. 通过绑定change事件,通过event.detail.current可以获取到当前点击索引。根据索引可以进行其他的操作。

本人的制作案例:

JSON文件:

"usingComponents": {
    "cat-bar":"../../components/category-x/category-x"
  },

wxml文件:

原创,如需转发,请先联系作者,微信A493116703

1 回复
回到顶部