最近在学习使用微信小程序,在做一个商家评分功能的时候,遇到一个比较棘手的问题,要实现的需求是可以点击、滑动选择评分等级,点击这个好说,监听bindtap事件确定是哪个星星(图片)被点击了就行。
可是要做滑动效果的话,就要用到bindtouchmove事件,在事件里可以拿到当前手指触摸点相对于页面的坐标值。通过动态获取这个坐标值,就可以得到跟星星图片的相对位置,从而修改评分参数。原理很简单,可是在实现的过程中却遇到了问题。然后大量搜索研究,都搜索不到,很多的是安卓和IOS平台,有自己专门的方法可以实现,小程序里并没有(当然可能是我学的时间短,还没有发现。。)。
我先把正确的做法放出来,然后再说下错误的是哪部分。里边的原理还不清楚,不知道是不是一个bug,当然更可能的是我研究不深入(笑哭.jpg)。
为了尽可能全面清晰地描述,我加了很多标注,并尽量精简了页面的元素。
我用的方法是使用wxss文件手动设置页面星星的位置,当然也可以用 wx.createSelectorQuery() 这个API动态,更精准地获取信息,不过为了能突出功能的实现(也因为比较忙),这个方法被略去了,如果有需要,我后期可以添加这部分内容。
wxml文件:
<view >
<block wx:for='{{scoreArray}}' wx:key='item' ><!-- 遍历评分列表 -->
<!-- 设置触摸事件和点击事件为同一个方法,否则点击却不滑动的话,不触发事件 -->
<view class='starLen' bindtouchmove='changeScore' bindtap='changeScore' >
<!-- 使用三目运算符来动态变化显示的是哪张图片,score是js中的分数,index是scoreArray的下标 -->
<!-- src部分可以这样写 src="{{score>index?'../../images/fullStar.png':'../../images/nullStar.png'}}" ,这样可以在js文件把fullStarUrl和nullStarUrl去掉 -->
<image class='star' src="{{score>index?fullStarUrl:nullStarUrl}}" />
</view>
</block>
<view class='scoreContent'>{{scoreContent}}</view><!-- 显示当前评分 -->
</view>
js文件:
Page({
data: {
fullStarUrl: '../../imagesfullStar.png', //满星图片
nullStarUrl: '../../images/nullStar.png', //空星图片
score: 0, //评价分数
scoreArray: [1, 2, 3, 4, 5], //分为1-5个评分层次
scoreText: ['1星', '2星', '3星', '4星', '5星'], //评分列表
scoreContent: '' //文字显示评分情况
},
changeScore: function(e) {
console.log(e)//控制台触摸事件信息
var that = this;
var num = 0;//临时数字,动态确定要传入的分数
var touchX = e.touches[0].pageX;//获取当前触摸点X坐标
var starMinX = 0;//最左边第一颗星的X坐标,假设距离页面距离为0
var starWidth = 30;//星星图标的宽度,假设30(已在wxss文件中设置".star")
var starLen = 10;//星星之间的距离假设为10(已在wxss文件中设置".starLen")
var starMaxX = starWidth * 5 + starLen * 4;//最右侧星星最右侧的X坐标,需要加上5个星星的宽度和4个星星间距
if (touchX > starMinX && touchX < starMaxX) {//点击及触摸的初始位置在星星所在空间之内
//使用Math.ceil()方法取得当前触摸位置X坐标相对于(星星+星星间距)之比的整数,确定当前点击的是第几个星星
num = Math.ceil((touchX - starMinX) / (starWidth + starLen));
if (num != that.data.score) {//如果当前得分不等于刚设置的值,才赋值,因为touchmove方法刷新率很高,这样做可以节省点资源
that.setData({
score: num,
scoreContent: that.data.scoreText[num - 1]
})
}
} else if (touchX < starMinX) {//如果点击或触摸位置在第一颗星星左边,则恢复默认值,否则第一颗星星会一直存在
that.setData({
score: 0,
scoreContent: ''
})
}
},
})
wxss文件:
.starLen{
margin-right: 10px;
display: inline-block;
}
.star{
width:30px;
height:30px;
vertical-align:text-bottom;
display: inline-block;
}
.scoreContent{
margin-left: 100px;
display: inline-block;
}
效果如下图,目前我还不会制作动态图,就先放个不动的,以后有需要就再传个gif:
至于之前所说有个问题,是在放图片位置使用了如下wxml代码:
<view class='starLen' >
<image wx:if='{{score>index}}' class='star' src='../../images/fullStar.png' />
<image wx:else class='star' src='../../images/nullStar.png' />
</view>
那个时候没有把图片地址放在js文件,而是直接放在这里,后来出问题实在解决不了,就用了上文的三目运算符的方法,从js传地址,这样倒是解决了问题,但还不清楚其中原理。。出现的问题是,点击星星时候,往后滑动是没问题的,在第一次按的星星右边可以来回滑动,可是只要滑回左侧,消除一颗星后,就会卡住bindtouchmove方法,此时怎么滑都没用了,只能松开手重新点击往后滑。
我也是参考网上资源资料学习的,深感有个一针见血方法的重要性,在获取这些资源的同时,我也愿意把自己的所见所得分享出来,抛砖引玉,希望能更进一步。如果感觉此文有用,请不吝赐赞~ O(∩_∩)O,而且如果发现文中内容有所纰漏,也请联系我尽快修改,谢谢大家~
对了,文中所用素材,也是网上搜索到的免费资源(如果真侵权了,还请联系我删除),自己裁了一下,如果有练习需要,我也放出来供大家使用~