uniapp微信小程序vue3封装时间段范围选择组件

一、前言

目前uni-ui组件的日期选择组件,有日期选择、日期范围选择、日期时间选择、日期时间范围选择,就是没有时间段的选择,懒的去找第三方插件,而我的需求就是简单的取一个时间段的范围,就自己封装了。

二、最终效果

三、参数配置

1、代码示例

html 复制代码
<TTimeRange v-model="time" v-model:show="showPicker" @confirm="onConfirm" @cancel="showPicker=false" />

2、组件使用

html 复制代码
<TInput
    title="每日可装车时段"
     inputType="select"
     v-model:select-value="state.orderMsg.loadTime"
     @clickInput="showPicker=true"
   />
<TTimeRange v-model:show="showPicker" @confirm="onConfirm" @cancel="showPicker=false" />

四、组件源码

html 复制代码
<template>
  <view class="t_time-range-picker">
    <!-- 遮罩层 -->
    <view class="mask" v-if="show" @tap="cancel"></view>

    <!-- 选择器容器 -->
    <view class="picker-container" v-if="show">
      <view class="picker-header">
        <text class="btn cancel" @tap="cancel">取消</text>
        <text class="btn clear" v-if="isShowClear" @tap="clearSelection">清空</text>
        <text class="title">选择时间段</text>
        <text class="btn confirm" @tap="confirm">确定</text>
      </view>

      <!-- 时间选择器 -->
      <picker-view
        class="picker-view"
        :value="pickerValue"
        @change="onPickerChange"
        indicator-style="height: 60rpx;"
      >
        <!-- 开始时间-小时 -->
        <picker-view-column>
          <view class="picker-item" v-for="(h, index) in hours" :key="index">{{ h }}时</view>
        </picker-view-column>

        <!-- 开始时间-分钟 -->
        <picker-view-column>
          <view class="picker-item" v-for="(m, index) in minutes" :key="index">{{ m }}分</view>
        </picker-view-column>

        <view class="separator">至</view>

        <!-- 结束时间-小时 -->
        <picker-view-column>
          <view class="picker-item" v-for="(h, index) in hours" :key="index">{{ h }}时</view>
        </picker-view-column>

        <!-- 结束时间-分钟 -->
        <picker-view-column>
          <view class="picker-item" v-for="(m, index) in minutes" :key="index">{{ m }}分</view>
        </picker-view-column>
      </picker-view>
    </view>
  </view>
</template>

<script setup lang="ts">
import { ref, computed, watch, reactive } from "vue";

const props = defineProps({
  // 组件显示状态
  show: {
    type: Boolean,
    default: false
  },
  isShowClear: {
    type: Boolean,
    default: false
  },
  // 双向绑定的时间段值
  modelValue: {
    type: Object as () => { start: string; end: string },
    default: () => ({ start: "00:00", end: "00:00" })
  }
});

const emit = defineEmits(["update:modelValue", "confirm", "cancel"]);

// 生成小时数组 (00-23)
const hours = Array.from({ length: 24 }, (_, i) => i.toString().padStart(2, "0"));

// 生成分钟数组 (00-59)
const minutes = Array.from({ length: 60 }, (_, i) => i.toString().padStart(2, "0"));

// picker-view的当前索引值 [开始小时, 开始分钟, 结束小时, 结束分钟]
const pickerValue = ref<number[]>([0, 0, 0, 0]);

// 当前选择的时间段
const timeRange = reactive({
  start: props.modelValue.start,
  end: props.modelValue.end
});

// 将时间字符串转换为picker索引
const timeToIndex = (time: string): number[] => {
  const [hour, minute] = time.split(":").map(Number);
  return [
    hours.findIndex(h => h === hour?.toString().padStart(2, "0")),
    minutes.findIndex(m => m === minute?.toString().padStart(2, "0"))
  ];
};

// 初始化picker值
const initPicker = () => {
  const startIdx = timeToIndex(timeRange.start);
  const endIdx = timeToIndex(timeRange.end);
  pickerValue.value = [...startIdx, ...endIdx];
};

// 监听显示状态变化
watch(
  () => props.show,
  val => {
    if (val) initPicker();
  }
);

// 监听外部传入的值变化
watch(
  () => props.modelValue,
  val => {
    timeRange.start = val.start;
    timeRange.end = val.end;
  }
);

// 选择器变化事件
const onPickerChange = (e: any) => {
  const values: number[] = e.detail.value;

  // 获取新选择的时间
  const newStart = `${hours[values[0]]}:${minutes[values[1]]}`;
  const newEnd = `${hours[values[2]]}:${minutes[values[3]]}`;

  // 时间有效性校验
  if (newStart > newEnd) {
    // 如果开始时间晚于结束时间,自动交换
    timeRange.start = newEnd;
    timeRange.end = newStart;
    pickerValue.value = [...timeToIndex(newEnd), ...timeToIndex(newStart)];
  } else {
    timeRange.start = newStart;
    timeRange.end = newEnd;
    pickerValue.value = values;
  }
};

// 确认选择
const confirm = () => {
  emit("update:modelValue", { ...timeRange });
  emit("confirm", { ...timeRange });
};

// 取消选择
const cancel = () => {
  initPicker(); // 重置为原始值
  emit("cancel");
};
// 清空选择的方法
const clearSelection = () => {
  // const defaultTime = { start: "00:00", end: "00:00" };
  timeRange.start = "";
  timeRange.end = "";
  initPicker(); // 更新 pickerValue 到默认值
  emit("update:modelValue", { ...timeRange });
};
defineExpose({ cancel, clearSelection });
</script>

<style  lang="scss" scoped>
.t_time-range-picker {
  position: relative;
  z-index: 999;
  .mask {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.5);
  }
  .picker-container {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: #fff;
    border-radius: 24rpx 24rpx 0 0;
    padding: 20rpx 0;
    .picker-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 20rpx 30rpx;
      border-bottom: 1rpx solid #eee;
      .title {
        font-size: 32rpx;
        font-weight: bold;
      }
      .btn {
        padding: 10rpx 30rpx;
        font-size: 32rpx;
      }

      .cancel {
        color: #101010;
      }
      .clear {
        color: #ff3b30;
      }

      .confirm {
        color: #007aff;
      }
    }
    .picker-view {
      height: 520rpx;
      margin-top: 20rpx;
      .picker-item {
        line-height: 50rpx;
        text-align: center;
        font-size: 30rpx;
      }
      .separator {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        font-size: 32rpx;
        color: #333;
      }
    }
  }
}
</style>

相关文章

基于ElementUi再次封装基础组件文档


vue3+ts基于Element-plus再次封装基础组件文档

相关推荐
533_8 小时前
[element-plus] el-tree 动态增加节点,删除节点
前端·javascript·vue.js
程序猿_极客8 小时前
Vue 2脚手架从入门到实战核心知识点全解析(day6):从工程结构到高级通信(附代码讲解)
前端·javascript·vue.js·vue2学习笔记
一只小阿乐9 小时前
vue3 使用v-model开发弹窗组件
javascript·vue.js·elementui
web加加9 小时前
vue3 +vite项目页面防f12,防打开控制台
前端·javascript·vue.js
KYumii11 小时前
智慧判官-分布式编程评测平台
vue.js·spring boot·分布式·spring cloud·java-rabbitmq
一人一程温一壶酒11 小时前
微信小程序uniapp开发附源码——图片加水印
微信小程序·uni-app·notepad++
长空任鸟飞_阿康11 小时前
AI 多模态全栈应用项目描述
前端·vue.js·人工智能·node.js·语音识别
码码哈哈0.012 小时前
Vue 3 + Vite 集成 Spring Boot 完整部署指南 - 前后端一体化打包方案
前端·vue.js·spring boot
humors22115 小时前
前端开发案例(不定期更新)
前端·vue.js·elementui·ruoyi·若依
一 乐17 小时前
校园墙|校园社区|基于Java+vue的校园墙小程序系统(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·后端·小程序