使用原生微信小程序picker-view封装实现一个自定义时间选择器

664 阅读2分钟

最近在搞B端小程序中遇到一个需求是限制当前时间选择器的开始时间为当前时间4小时前,结束时间为当前时间,由于有固定风格的UI,无法使用原生小程序及其他第三方组件来实现该需求,因此就只能使用picker-view自定义封装一个组件,该文主要记录实现,废话不多说,直接上代码~

  1. 项目根目录下创建components文件夹,新建名为time-picker的文件夹,右键新建组件,输入名称index(可以自定义,我这里输的是index,按团队定的规范来的)自动创建相关.wxss.js.wxml.json文件相关代码如下:
// index.js

Component({
  data: {
    // 可供选择的小时范围
    hours: [],
    // 可供选择的分钟范围
    minutes: [],
    // 当前选择的小时
    selectedHour: '00',
    // 当前选择的分钟
    selectedMinute: '00',
    // 当前选择的小时在可供选择的小时范围中的索引
    hourIndex: 0,
    // 当前选择的分钟在可供选择的分钟范围中的索引
    minuteIndex: 0,
    disabled: false,
  },
  lifetimes: {
    attached: function() {
      this.initDate()
    },
  },
  methods: {
    initDate() {
      const now = new Date();
      const nowTime = new Date(now.getTime());
      const start = new Date(now.getTime() - 4 * 60 * 60 * 1000);
      const hours = [];
      const minutes = [];
      let startMinute = nowTime.getMinutes();
      // 当前小时大于等于4时,往前推4小时,小于4时,只往前推从0点到当前时间的间隔
      if(nowTime.getHours()>=4) {
        for (let i = start.getHours(); i <= nowTime.getHours(); i++) {
          hours.push(i.toString().length<2?'0'+i:i.toString());
        }
        
        for (let i = 0; i <= startMinute; i++) {
          minutes.push(i.toString().length<2?'0'+i:i.toString());
        }
        this.setData({
          hours,
          minutes,
        });
      } else {
        for (let i = 0; i <= nowTime.getHours(); i++) {
          hours.push(i.toString().length<2?'0'+i:i.toString());
        }
        for (let i = 0; i <= startMinute; i++) {
          minutes.push(i.toString().length<2?'0'+i:i.toString());
        }
        this.setData({
          hours,
          minutes,
        });
      }
      this.setData({
        hourIndex:hours.length - 1,
        minuteIndex:minutes.length - 1,
        selectedHour: hours[hours.length - 1],
        selectedMinute: minutes[minutes.length - 1]
      })
    },
    // 当选择的小时发生变化时更新当前选择的小时和分钟范围
    bindHourChange: function(event) {
      const { value } = event.detail;
      const { hours } = this.data;
      const selectedHour = hours[value];
      // 根据当前选择的小时更新可供选择的分钟范围
      const now = new Date();
      const nowTime = new Date(now.getTime());
      const start = new Date(now.getTime() - 4 * 60 * 60 * 1000);
      let startMinute = 0;
      if (selectedHour == nowTime.getHours()) {
        const minutes = [];
        startMinute = nowTime.getMinutes();
        for (let i = 0; i <= startMinute; i++) {
          minutes.push(i.toString().length<2?'0'+i:i.toString());
        }
        this.setData({
          selectedHour, 
          minutes,
          hourIndex: value,
        });
      } else if(selectedHour == start.getHours()) {
        const minutes = [];
        startMinute = start.getMinutes();
        for (let i = 0; i <= startMinute; i++) {
          minutes.push(i.toString().length<2?'0'+i:i.toString());
        }
        this.setData({
          selectedHour, 
          minutes,
          hourIndex: value,
        });
      } else {
        const minutes = [];
        for (let i = 0; i < 60; i++) {
          minutes.push(i.toString().length<2?'0'+i:i.toString());
        }
        this.setData({
          selectedHour, 
          hourIndex: value,
          minutes,
        });
      } 
    },

    // 当选择的分钟发生变化时更新当前选择的分钟
    bindMinuteChange: function(event) {
      const { value } = event.detail;
      this.setData({
        selectedMinute: this.data.minutes[value],
        minuteIndex: value,
      });
      
    },
    // 监听pickstart事件禁用提交按钮
    handlePickStart () {
      this.setData({
        disabled: true
      })
    },
    // 监听pickend事件恢复提交按钮
    handlePickEnd () {
      this.setData({
        disabled: false
      })
    },
    // 提交响应给父组件的数据
    handleSubmit() {
      const now = +new Date()
      this.triggerEvent('change', {
        value: `${this.data.selectedHour}:${this.data.selectedMinute}`,
      });
    }
  },
});
index.json
{
  "component": true,
  "usingComponents": {}
}
<!-- index.wxml -->
<view class="time-selector">
  <picker-view class="picker-view" bindchange="bindHourChange" value="{{[hourIndex]}}" bindpickstart="handlePickStart" bindpickend="handlePickEnd"> 
    <picker-view-column class="picker-view-column">
      <view class="view" wx:for="{{ hours }}" wx:key="index">{{ item }} 时</view>
    </picker-view-column>
  </picker-view>
  <picker-view class="picker-view" bindchange="bindMinuteChange" value="{{[minuteIndex]}}" bindpickstart="handlePickStart" bindpickend="handlePickEnd">
    <picker-view-column class="picker-view-column">
      <view class="view" wx:for="{{ minutes }}" wx:key="index">{{ item }} 分</view>
    </picker-view-column>
  </picker-view>
</view>
<button bindtap="handleSubmit" disabled="{{disabled}}">确定</button>
// index.css文件
.time-selector {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 220rpx;
}

.picker-view {
  width: 100%;
  height: 100%;
}

.picker-view-column {
  width: 50%;
}

.picker-view-column:first-child {
  text-align: center;
}

.picker-view-column:last-child {
  text-align: center;
}

.view {
  font-size: 28rpx;
  color: #666;
  display: flex;
  align-items: center;
  justify-content: center;
}
  1. 根目录pages下找到要使用这个组件的页面的相关目录的.json文件,我这里是pages/index文件夹下将声明组件的引用,代码如下:

    pages/index文件夹下index.json文件

{
  "usingComponents": {
  //注意相对路径和绝对路径
    "time-picker": "../../components/time-picker/index"
  }
}
  1. 在pages/index文件下index.js 写一个方法onTimeChange用于接收时间选择器抛出的结果

Page({
  data: {
    
  },

  onLoad () {

  },

  onTimeChange (e) {
    // 选择器所抛出的结果
    console.log(e.detail.value)
  }
})
  1. 在pages/index文件夹下index.wxml文件下使用声明的组件
<view>
  <time-picker bind:change="onTimeChange" />
</view>

至此所有代码都以粘贴完毕了,如果有问题欢迎👏指正,转载请指明出处,谢谢!