基于scroll-view横向滚动制作的类目表组件
在电商项目中经常用到的就是一些类别滚动条,例如在某多以及某宝中在首页非常常见。
上面顶部下面就采用了这种滚动条的效果。
原理:
首先获取scroll-view中内容的实际宽度,然后计算出scrollLeft的最大值,然后根据用户点击的位置,判断当前点击是在左边还是右边(我们以屏幕的中点为分割线,中点左侧为左边,中点右侧为右边),同时根据点击方向判断移动方向(点击左侧向右移动,点击右侧像左移动),然后我们获取被点后当前的scrollLeft值,然后获取被点击元素的宽度以及被点击元素的left值,计算出需要移动的距离,改变现有的scollLeft值。如果向右移动后的scollLeft值超过最大的scollLeft值,我们就取scrollLeft的最大值。如果向左移动scollLeft值小于0,我们就取零。
下面是组件的制作过程:
- 首先创建category-x的组件目录,然后生成组件文件。
- 相关代码
WXML代码:
<view class="catbar" style="height:{{height}}rpx">
<scroll-view class="categories" scroll-x="{{true}}" scroll-left="{{scrollLeft}}" scroll-with-animation="{{true}}"
scroll-anchoring="{{true}}">
<block wx:for="{{categoriesData}}" wx:for-item="item" wx:for-index="index" wx:key="*this">
<view class="category" style="padding-right:{{paddingRight}}rpx;padding-left:{{index==0?firstPaddingLeft:0}}"
bind:tap="onChanging" data-index="{{index}}">
<text class="category-name {{nowIndex==index?'current-category':''}}">{{item}}</text>
</view>
</block>
</scroll-view>
</view>
wxss代码:
/* components/category-x/category-x.wxss */
.catbar{
width:100%
}
.categories{
height:100%;
white-space: nowrap;
box-sizing: border-box;
border-bottom: 2rpx solid #f6f6f6;
-webkit-overflow-scrolling: touch;
}
.category {
display: inline-block;
box-sizing: border-box;
height: 100%;
}
.category:first-child {
padding-left: 20rpx;
}
.category-name{
display: inline-block;
box-sizing: border-box;
width: 100%;
height: 100%;
font-size: 32rpx;
line-height: 80rpx;
color: #353535;
}
.current-category {
color: #e64340;
border-bottom: 6rpx solid #e64340;
}
JS代码:
// components/category-x/category-x.js
Component({
/**
* 组件的属性列表
*/
properties: {
//category bar的高度,单位为rpx
height: {
type: Number,
value: 0
},
//设置横向滚动条位置
scrollLeft: {
type: Number,
value: 0
},
//数据
categoriesData: {
type: Array,
value: []
},
//当前索引
nowIndex: {
type: Number,
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:
- 在page.json中引入组件后,height值为必填,categories-data为必填值。其余为不强制。默认值通过观察js中的properties可以看出。
- 通过绑定change事件,通过event.detail.current可以获取到当前点击索引。根据索引可以进行其他的操作。
本人的制作案例:
JSON文件:
"usingComponents": {
"cat-bar":"../../components/category-x/category-x"
},
wxml文件:
原创,如需转发,请先联系作者,微信A493116703