[UI组件] 来做一个可配置的滑块进度条吧
在一些需要用户填写资料的业务场景中,有时会让用户选择某个业务的范围,这时就需要用到滑块进度条。然后你们最爱的产品经理会说,给我整一个颜色可控,滑块按钮可大可小,滑块边框也要可大可小的滑动条来.. emmm,一看这样的设计需求就意味着小程序原生的slider组件就不能用了。因为这玩意在样式上就不能自由的配置,只好来手动实现一个。 结构设计
行吧,那说干就干。首先滑动条可以从俯视图角度来看,分为三层。分别是 在结构设计中,可以将
点击行为事件滑块进度条的
在组件外部容器中绑定一个点击事件,我们必须得要知道用户点击位置,在 得到两个关键数据后,将用户点击的位置 如下图所示:
// ...
/**
* 组件的初始数据
*/
data: {
containerInfo: null,percentage: // 取到滑块进度条的位置信息
wx.createSelectorQuery().in(this)
.select('.slider-wrap')
.boundingClientRect((rect) => {
if (!rect) return;
this.data.container = rect;
this._initBloackPos();
}).exec()
},136);">// 点击进度条
tappingSlider(evt) {
const { containerInfo } = this.data;
if (!containerInfo) return;
const { clientX } = evt.changedTouches[0];
const { digits,_maxDistance } = this.data;
// 需要做边界处理
const perc = this._computeOffset(clientX,containerInfo.left,100);
const percentage = this._boundaryHandler(perc);
this.setData({ percentage });
this.triggerEvent('change',{
value: percentage.toFixed(digits) * 1
});
},136);">/**
* 计算相对容器的偏移距离
*
* @param { Number } x - X 坐标
* @param { Number } offset - 偏移量
* @param { Number } maxVal - 在 maxVal 范围内求百分比
*/
_computeOffset(x,offset,maxVal) {
const { width } = this.data.containerInfo;
// 底层保证一定精度
return (((x - offset) / width) * maxVal).toFixed(4) * 1;
},136);">/**
* 边界处理
* @param { Number } num - 待处理的最值
* @param { Number } maxNum - num 最大值
* @param { Number } minNum - num 最小值
*/
_boundaryHandler(num,maxNum = 100,minNum = 0) {
return num > maxNum ? maxNum : (num < minNum ? minNum : num);
},68);">"tappingSlider" bindtouchmove="onTouchMove">
<view
"silder-bg-inner"
"width: {{percentage}}%; height: {{height}}rpx;"
>"left: {{percentage}}%;width: {{blockSize}}rpx;height: {{blockSize}}rpx; border-width: {{blockBorderWidth}}rpx;"
></view>
虽然实现了点击滑动到指定位置的功能,但仔细一看还是有一些瑕疵的~ 当我们点击到百分百时, 超出的原因是因为在布局上,我们使用绝对定位 在文章开头我们已经暴露了一个
如此,该事件就完成啦~ 滑动事件完成点击事件后,我们还得让它能进行自由的滑动。进度条组件的拖动的流程大致是: 因此跟H5的思路一样,我们只需监听 首先先监听 Component({
methods: {
onTouchStart(evt) {
this.data.moving = true;
// 记录原始坐标
this.data.originPos = this.data._blockOffset;
this.data.originPercentage = this.data.percentage;
this.data._startTouchX = evt.changedTouches[0].clientX;
},136);">// 滑块移动
onTouchMove(evt) {
const { moving,containerInfo } = this.data;
if (!moving || !containerInfo) return;
const { clientX } = evt.changedTouches[0];
const {
digits,originPos,originPercentage,_startTouchX,_maxDistance
} = this.data;
// 计算偏移量
const computeOffset = (maxVal) => {
return this._computeOffset(clientX,136);">// 实际百分比
const perc = originPercentage + computeOffset(100);
const percentage = this._boundaryHandler(perc);
// 滑块偏移度
const offset = originPos + computeOffset(_maxDistance);
const _blockOffset = this._boundaryHandler(offset,_maxDistance);
this.setData({ percentage,_blockOffset });
this.triggerEvent(value: percentage.toFixed(digits) * 1
});
},onTouchEnd(evt) {
this.data.moving = false;
},}
})
总结 |