小程序滑动选择

152 阅读1分钟

效果

1.gif

实现环境

  • abcdefg相对于屏幕是居中的,并且不会换行(换行的话要考虑Y坐标)
  • 每个item都是相同宽高间距

思路

1、屏幕左边框对应内容第一项的距离a 的距离可以计算出来(我下面命名为leftX)
2、用户移动时我们能获取到手指相对于页面的坐标(获取的是pageX,pageY)
3、用户手指X坐标减去 leftX再除以item的宽 + item的一个左边距再向上取整= 当前用户手指所在的项的序号 ( Math.ceil((fingerPosition.x - leftX) / (letterItem.width+letterItem.margin)) - 1 )

代码

wxml

<view class="word-box">
  <view class="word-item {{item.checked?'checked':''}}" style="{{wordItemStyle}}" wx:for="{{letterList}}" wx:key="index" bindtouchstart="onItemStart" bindtouchmove="onItemMove" bindtouchend="onItemEnd" data-idx="{{index}}">
    {{item.text}}
  </view>
</view>

wxss

.word-box{
  display: flex;
  display: -webkit-flex;
  justify-content: center;
  align-items: center;
  width: 750rpx;
  margin: 20rpx auto;
}
.word-item{
  display: flex;
  display: -webkit-flex;
  justify-content: center;
  align-items: center;
  border: 1rpx solid red;
  box-sizing: border-box;
}
.checked{
  background: #000;
  color: #fff;
}

js

const app = getApp()
Page({
  data: {
    letterList:[
      {
        text:'a',
        checked:false,
      },
      {
        text:'b',
        checked:false,
      },
      {
        text:'c',
        checked:false,
      },
      {
        text:'d',
        checked:false,
      },
      {
        text:'e',
        checked:false,
      },
      {
        text:'f',
        checked:false,
      },
      // {
      //   text:'g',
      //   checked:false,
      // },
    ],
    letterItem:{
      width:80,
      margin:5,
    },
    canMove:true,
  },
  onLoad: function (options) {
    const SystemInfo = wx.getSystemInfoSync()
    app.globalData.pxToRpx = 750/SystemInfo.windowWidth

    let letterItem= this.data.letterItem
    let wordItemStyle = `width:${letterItem.width}rpx;height:${letterItem.width}rpx;margin:${letterItem.margin}rpx;`
    this.setData({
      wordItemStyle
    })
  },
  onItemStart(e){
    console.log('onItemStart',e)
    let idx = e.currentTarget.dataset.idx
    let letterList = this.data.letterList
    for(let i=idx;i<letterList.length;i++){
      if(letterList[i].checked){
        this.data.canMove = false
        wx.showToast({
          title: '选了后面的不能再选前面!',
          icon:'none'
        })
        return false
      }
    }
    this.setData({
      [`letterList[${idx}].checked`]:!this.data.letterList[idx].checked
    })
  },
  preCheckIdx:0,   // 上一次触发onItemMove所在的idx
  onItemMove(e){
    // console.log(e)
    if(!this.data.canMove) return 
    const pxToRpx = app.globalData.pxToRpx
    let idx = e.currentTarget.dataset.idx
    let letterList = this.data.letterList

    let fingerPosition = {
      x:e.touches[0].pageX * pxToRpx,
      y:e.touches[0].pageY * pxToRpx,
    }
    console.log('onItemMove fingerPosition',fingerPosition)
    
    let letterItem = this.data.letterItem
    let leftX = (750 - (letterList.length*letterItem.width + (letterList.length-1)*letterItem.margin ))/2
    let checkedNum = Math.ceil((fingerPosition.x - leftX) / (letterItem.width+letterItem.margin)) - 1    // 当前滑动到的下标
    console.log( idx,'-',checkedNum )
    // console.log(leftX)
    
    if(checkedNum<idx || this.preCheckIdx == checkedNum || checkedNum>letterList.length-1){
      // 往左划  或者 上一次位置和这次位置一致 则不奏效
      return false
    }
    if(this.preCheckIdx > checkedNum){
      this.setData({
        [`letterList[${this.preCheckIdx}].checked`]:false
      })
    }
    if(this.preCheckIdx < checkedNum){
      this.setData({
        [`letterList[${checkedNum}].checked`]:true
      })
    }
    this.preCheckIdx = checkedNum
  },
  onItemEnd(e){
    // console.log('onItemEnd',e)
    this.data.canMove = true
  },
})