基于 uView 的 u-picker 自定义时分秒选择器实现(支持反显)

在 uni-app 开发中,uView 作为主流的 UI 组件库,其u-timepicker时间选择器组件能满足大部分时间选择场景,但在需要精确到秒 的业务场景中(如烹饪步骤耗时、视频剪辑时间点、设备操作时长等),u-timepicker仅支持时分选择的限制就无法满足需求。本文将分享基于u-picker自定义实现支持时分秒选择 + 反显的时间选择器,解决秒级选择的业务痛点。

一、实现思路

核心思路是基于 uView 的u-picker基础选择器,手动构建时分秒三列数据,同时实现 "时间字符串→选择器索引" 的解析逻辑(支持反显),以及 "选择器索引→时间字符串" 的拼接逻辑(支持确认更新),具体拆解为以下步骤:

  1. 基于u-picker搭建选择器基础结构,通过show控制显隐;
  2. 封装列数据生成函数,构建 "小时(00-23)、分钟(00-59)、秒(00-59)" 三列标准数据;
  3. 实现时间字符串解析函数,将业务中已有的时间(如02:01:00)转换为选择器列索引,支持反显;
  4. 处理选择器确认 / 取消事件,更新业务数据并保证响应式,同时做边界校验避免异常。

二、核心代码实现与解析

1. 模板结构:u-picker 基础布局

首先搭建u-picker的基础模板,绑定核心属性和事件,同时添加触发选择器的按钮:

vue

xml 复制代码
<template>
  <!-- 自定义时分秒选择器 -->
  <u-picker 
    :show="showPickerVis"
    :columns="timeColumns" 
    :defaultIndex="defaultIndex"
    @cancel="handleClosePicker"
    @confirm="handleConfirm">
  </u-picker>
  
  <!-- 触发选择器的按钮(示例:烹饪步骤耗时选择) -->
  <view class="time-select" @tap="showTimePicker(step, index)"></view>
</template>

关键属性说明:

  • show:控制选择器显隐;
  • columns:选择器的列数据(时分秒三列);
  • defaultIndex:默认选中的索引(实现反显的核心);
  • @cancel/@confirm:取消 / 确认选择的事件回调。

2. 数据初始化:定义核心响应式数据

data中定义选择器运行所需的核心数据,保证响应式:

javascript

运行

javascript 复制代码
data() {
  return {
    showPickerVis: false, // 选择器显隐状态
    currentTimeStepIndex: -1, // 当前操作的业务数据索引(如烹饪步骤索引)
    timeColumns: [], // 时分秒列数据([[小时], [分钟], [秒]])
    defaultIndex: [0,0,0], // 选择器默认索引(反显用)
    formData: {
      cookingSteps: [] // 业务数据示例:烹饪步骤列表,含estSpendTime(耗时)字段
    }
  }
}

3. 列数据生成:构建标准时分秒列

封装fillTimeColumns函数,生成标准化的时分秒列数据,保证格式统一(两位数字,不足补 0):

javascript

运行

scss 复制代码
fillTimeColumns(initialArr = [[], [], []]) {
  // 辅助函数:数字补零(如1→01)
  const padZero = (num) => num.toString().padStart(2, '0')
  
  // 生成小时列(00-23):兼容初始数据,无数据则重新生成
  const hoursColumn = initialArr[0].length === 24 
    ? initialArr[0] 
    : Array.from({ length: 24 }, (_, index) => padZero(index));
  
  // 生成分钟/秒列(00-59)
  const minuteSecondColumn = Array.from({ length: 60 }, (_, index) => padZero(index));
  
  // 赋值给列数据,供u-picker渲染
  this.timeColumns = [    hoursColumn,    minuteSecondColumn,    minuteSecondColumn  ]
}

核心逻辑:

  • padZero保证所有时间单位都是两位字符串(如05而非5),避免格式混乱;
  • 小时列限制为 00-23,分秒列限制为 00-59,符合时间规范;
  • 兼容初始数据,若已有完整小时列则复用,否则重新生成,提升灵活性。

4. 反显核心:时间字符串转选择器索引

封装getTimeColumnIndexes函数,将业务中的时间字符串(如02:01:0002:01:00)解析为选择器的列索引,实现反显:

javascript

运行

javascript 复制代码
/**
 * 根据时间字符串获取时分秒在timeColumns中的对应索引
 * @param {string} timeStr - 时间字符串,格式如 "02:01:00"(中文冒号)或 "02:01:00"(英文冒号)
 * @param {Array<Array<string>>} timeColumns - 时分秒列数据
 * @returns {Array<number>} [小时索引, 分钟索引, 秒索引]
 */
getTimeColumnIndexes(timeStr, timeColumns) {
  // 边界校验:列数据异常则返回默认索引
  if (!Array.isArray(timeColumns) || timeColumns.length < 3) {
    console.warn('timeColumns格式异常');
    return [0, 0, 0];
  }

  // 统一分隔符(兼容中文/英文冒号),分割为时/分/秒
  const timeParts = timeStr.replace(/:/g, ':').split(':');
  
  // 格式校验:必须是HH:MM:SS格式
  if (timeParts.length !== 3 || !/^\d{2}$/.test(timeParts[0]) || !/^\d{2}$/.test(timeParts[1]) || !/^\d{2}$/.test(timeParts[2])) {
    console.warn('时间格式错误,应为 "HH:MM:SS" 或 "HH:MM:SS"');
    return [0, 0, 0];
  }

  const [hourStr, minuteStr, secondStr] = timeParts;
  // 查找对应索引,找不到则返回0
  const hourIndex = timeColumns[0].findIndex(item => item === hourStr) || 0;
  const minuteIndex = timeColumns[1].findIndex(item => item === minuteStr) || 0;
  const secondIndex = timeColumns[2].findIndex(item => item === secondStr) || 0;

  return [hourIndex, minuteIndex, secondIndex];
}

核心逻辑:

  • 兼容中英文冒号,解决业务中时间字符串格式不统一的问题;
  • 严格的格式校验,避免非法时间字符串导致选择器异常;
  • 从列数据中精准查找索引,保证反显的准确性。

5. 事件处理:打开 / 确认 / 关闭选择器

(1)打开选择器:记录索引 + 设置反显

javascript

运行

kotlin 复制代码
showTimePicker(step, index) {
  // 1. 解析当前步骤的时间字符串,设置反显索引
  this.defaultIndex = this.getTimeColumnIndexes(step.estSpendTime, this.timeColumns);
  // 2. 记录当前操作的业务数据索引(如烹饪步骤索引)
  this.currentTimeStepIndex = index;
  // 3. 显示选择器
  this.showPickerVis = true;
}

打开选择器时,先解析当前业务数据的时间字符串,设置defaultIndex实现反显,同时记录当前操作的索引,为后续更新数据做准备。

(2)确认选择:更新业务数据

javascript

运行

kotlin 复制代码
handleConfirm(e) {
  // 1. 边界校验:避免索引越界
  if (this.currentTimeStepIndex < 0 || this.currentTimeStepIndex >= this.formData.cookingSteps.length) {
    this.showPickerVis = false;
    return;
  }

  // 2. 拼接选择的时分秒为标准字符串
  const [hour, minute, second] = e.value;
  const estSpendTime = `${hour}:${minute}:${second}`;

  // 3. $set更新响应式数组(关键:保证数据响应式)
  this.$set(
    this.formData.cookingSteps[this.currentTimeStepIndex],
    'estSpendTime',
    estSpendTime
  );

  // 4. 关闭选择器
  this.showPickerVis = false;
}

核心注意点:

  • 必须做索引边界校验,避免操作不存在的业务数据;
  • 使用this.$set更新数组元素,保证 Vue 响应式(直接修改数组元素无法触发视图更新);
  • 拼接时间字符串为标准HH:MM:SS格式,统一业务数据格式。

(3)取消 / 关闭选择器

javascript

运行

ini 复制代码
handleClosePicker() {
  this.showPickerVis = false;
}

取消选择时仅隐藏选择器,不修改业务数据,保证操作的合理性。

三、使用说明

  1. 初始化列数据 :在页面onLoadonShow中调用fillTimeColumns(),初始化时分秒列数据:

javascript

运行

javascript 复制代码
onLoad() {
  this.fillTimeColumns();
}
  1. 业务数据适配 :将示例中的formData.cookingSteps替换为实际业务数据(如订单耗时、视频时长等),保证数据结构中包含时间字段(如estSpendTime);
  2. 样式调整 :根据业务需求调整u-picker和触发按钮的样式,适配页面 UI。

四、总结

本文基于 uView 的u-picker组件,实现了支持时分秒选择 + 反显 的自定义时间选择器,解决了u-timepicker不支持秒选择的痛点。核心亮点在于:

  1. 兼容中英文冒号的时间字符串解析,适配不同格式的业务数据;
  2. 完善的边界校验,避免索引越界、格式错误等异常场景;
  3. 保证 Vue 响应式更新,避免数据修改后视图不刷新的问题。

该自定义选择器可复用性强,适用于烹饪步骤耗时、设备操作时长、视频剪辑时间点等需要秒级时间选择的场景,只需稍作调整即可适配不同业务场景的时间选择需求。

相关推荐
00后程序员张2 小时前
Fastlane 结合 开心上架,构建跨平台可发布的 iOS 自动化流水线实践
android·运维·ios·小程序·uni-app·自动化·iphone
游戏开发爱好者82 小时前
iOS 性能测试的工程化方法,构建从底层诊断到真机监控的多工具测试体系
android·ios·小程序·https·uni-app·iphone·webview
2501_916008892 小时前
iOS App 混淆的真实世界指南,从构建到成品 IPA 的安全链路重塑
android·安全·ios·小程序·uni-app·cocoa·iphone
一路向前的月光3 小时前
Uniapp实现钉钉小程序前期基础配置
uni-app·钉钉
2501_915106323 小时前
iPhone 耗电异常全面诊断指南,构建多工具协同的电量分析与优化体系
android·ios·小程序·https·uni-app·iphone·webview
速易达网络3 小时前
Uniapp + Coze旅游AI平台应用实现方案
uni-app·旅游
2501_915909065 小时前
Fiddler抓包与接口调试实战,HTTPHTTPS配置、代理设置与移动端抓包详解
前端·测试工具·ios·小程序·fiddler·uni-app·webview
iOS阿玮12 小时前
不踩坑!苹果开发者账号:公司号和个人号,到底该怎么选?
uni-app·app·apple
2501_9151063213 小时前
如何查看手机使用记录:Android和iOS设备全面指南
android·ios·智能手机·小程序·uni-app·iphone·webview