实现一个 时间选择器 组件

实现一个 时间选择器 组件实现一个日周月年的筛选时间的组件 包括功能有切换上一日周月年 下一日周月年

大家好,欢迎来到IT知识分享网。

实现一个时间选择器组件

场景
技术栈(思路都是一样的)
  1. uniapp + vue3 + nutui
  2. uniapp + vue3 + uview plus
实现
  1. 第一层切换 日 周 月 年

思路:-自己封装html元素,可以更好定义样式和处理逻辑

//我这里随便写的 <view class="tab-item" v-for="(tab, i) in tabs" :class='selectIndex == i?"selectClass":""' :key="i" @tap.stop="tabClick(i,tab)">{ 
   { 
   tab}}</view> var tabs = ['日','周','月','年' ] var selectIndex = 0 //默认选中 tabClick(index,tab){ 
    selectIndex = index } .selectClass{ 
    font-size:50rpx; color:white; } 
  1. 实现第二层和第三层筛选,(我这里单独将这俩层封装成了组件,所有第1点的实现之后需要通过组件传值给到这里,用的组件库是nutui)
// 因为nutui的周选择有现成的日历组件,不用另外写逻辑,所以我这里就将他们区分 <template> <view class="time-picker_wrap"> <!----> <view class="left_btn" @tap="preTime"></view> <!----> <view class="timer_btn" @tap="handleTap">{ 
   { 
    timer }}</view> <!----> <view class="right_btn" @tap="nextTime"></view> <!-- 日、月选择 --> <nut-popup v-model:visible="show" position="bottom" safe-area-inset-bottom> <nut-date-picker v-model="pickerTime" is-show-chinese @confirm="onConfirm" :type="type" @cancel="show = false" > </nut-date-picker> </nut-popup> <!-- 周选择 --> <nut-calendar v-model:visible="isVisible" :default-value="pickerTime" type="week" :start-date="`2000-01-01`" :end-date="endTime" @close="closeSwitch()" @choose="setChooseValue"> </nut-calendar> <!----> <nut-popup v-model:visible="isPickerVisible" position="bottom" safe-area-inset-bottom> <nut-picker :columns="columns" @confirm="onYearConfirm"></nut-picker> </nut-popup> </view> </template> <script setup name='time-picker'> import { 
    ref, reactive, onMounted, defineProps, watch, defineEmits } from 'vue' //值 const timer = ref('') //储存日、月选择的值,用来进行转换 const pickerTime = ref('') //控制日、月选择器的显示隐藏 const show = ref(false) //控制周日历选择器的显示隐藏 const isVisible = ref(false) //控制年选择器的显示隐藏 const isPickerVisible = ref(false) //默认显示类型 const type = ref('week') //周选择器最大可选时间 const endTime = ref('') //年选择器的默认值 const columns = ref([]) //父组件传值 const props = defineProps({ 
    selectTab: String }) onMounted(() => { 
    if (type.value == 'year-month') { 
    timer.value = formatMonth(new Date()) pickerTime.value = timer.value } else if (type.value == 'date') { 
    timer.value = getNowTimer() pickerTime.value = timer.value } else if (type.value == 'week') { 
    timer.value = formatWeek(new Date()) pickerTime.value = timer.value.split(' - ') endTime.value = pickerTime.value[1] } else { 
    const currentYear = new Date().getFullYear() // 获取当前年份 const startYear = 2000 // 开始年份 timer.value = currentYear // 生成年份数组 columns.value = Array.from({ 
    length: currentYear - startYear + 1 }, (v, i) => ({ 
    text: startYear + i, value: startYear + i })) } }) watch(() => props.selectTab, (newValue) => { 
    if (newValue == 'month') { 
    type.value = 'year-month' timer.value = formatMonth(new Date()) pickerTime.value = timer.value } else if (newValue == 'day') { 
    type.value = 'date' timer.value = getNowTimer() pickerTime.value = timer.value } else if (newValue == 'week') { 
    type.value = 'week' timer.value = formatWeek(new Date()) pickerTime.value = timer.value.split(' - ') endTime.value = pickerTime.value[1] } else { 
    type.value = 'year' const currentYear = new Date().getFullYear() // 获取当前年份 const startYear = 2000 // 开始年份 timer.value = currentYear // 生成年份数组 columns.value = Array.from({ 
    length: currentYear - startYear + 1 }, (v, i) => ({ 
    text: startYear + i, value: startYear + i })) } }, { 
    immediate: true, deep: true } ) const emits = defineEmits(['changeTime']) watch(() => timer.value, (newValue) => { 
    if (type.value == 'date') { 
    const obj = { 
    startDate: newValue, endDate: newValue } emits('changeTime', obj) } else if (type.value == 'week') { 
    const [startDate, endDate] = newValue.split(' - ') emits('changeTime', { 
    startDate, endDate }) } else if (type.value == 'year-month') { 
    emits('changeTime', getStartAndEndOfMonth(newValue)) } else { 
    emits('changeTime', getStartAndEndOfYear(newValue)) } }) const getStartAndEndOfMonth = (dateString) => { 
    // 拆分年份和月份 const [year, month] = dateString.split('-').map(Number) // 将字符串转换为数字 // 获取该月份的开始日期 const startDate = new Date(year, month - 1, 1) // 1号 // 获取下一个月的 0 日,即上一个月的最后一天 const endDate = new Date(year, month, 0) return { 
    startDate: formatDate(startDate), // 格式化为 YYYY-MM-DD endDate: formatDate(endDate), // 格式化为 YYYY-MM-DD } } const getStartAndEndOfYear = (year) => { 
    const startDate = new Date(year, 0, 1) // 1月1日 const endDate = new Date(year + 1, 0, 0) // 下一个年的 0 日,即上一个年的最后一天 return { 
    startDate: formatDate(startDate), // 格式化为 YYYY-MM-DD endDate: formatDate(endDate), // 格式化为 YYYY-MM-DD } } // 处理点击事件 const handleTap = () => { 
    if (type.value == 'week') { 
    isVisible.value = true } else if (type.value == 'year') { 
    isPickerVisible.value = true } else { 
    show.value = true } } // 获取当前日期 const getNowTimer = () => { 
    const date = new Date() return formatDate(date) } // 获取当前月份 const formatMonth = (date) => { 
    let year = date.getFullYear() let month = String(date.getMonth() + 1).padStart(2, '0') return `${ 
     year}-${ 
     month}` // 格式化为 YYYY-MM } // 格式化日期为 YYYY-MM-DD const formatDate = (date) => { 
    let year = date.getFullYear() let month = String(date.getMonth() + 1).padStart(2, '0') let day = String(date.getDate()).padStart(2, '0') return `${ 
     year}-${ 
     month}-${ 
     day}` // 格式化为 YYYY-MM-DD } // 格式化为当前周的起始日期(周日为一周的开始) const formatWeek = (date) => { 
    const startOfWeek = new Date(date) const day = startOfWeek.getDay() // 获取当前日期是周几,周日是 0 startOfWeek.setDate(startOfWeek.getDate() - day) // 周日作为开始 const endOfWeek = new Date(startOfWeek) endOfWeek.setDate(endOfWeek.getDate() + 6) // 结束日期为下周六 return formatDate(startOfWeek) + ' - ' + formatDate(endOfWeek) // 返回格式化的日期范围 } // 获取前一个月或前一天/前一周的日期 const preTime = () => { 
    const minDate = new Date('2000-01-01') // 设置最小日期为2000年1月1日 if (type.value === 'year-month') { 
    const currentMonth = new Date(timer.value + '-01') currentMonth.setMonth(currentMonth.getMonth() - 1) // 判断是否小于最小日期 if (currentMonth >= minDate) { 
    timer.value = formatMonth(currentMonth) pickerTime.value = timer.value } } else if (type.value === 'week') { 
    const currentWeekStart = new Date(timer.value.split(' - ')[0]) currentWeekStart.setDate(currentWeekStart.getDate() - 7) // 判断是否小于最小日期 if (currentWeekStart >= minDate) { 
    timer.value = formatWeek(currentWeekStart) pickerTime.value = timer.value.split(' - ') endTime.value = pickerTime.value[1] } } else if (type.value === 'year') { 
    if (timer.value > 2000) { 
    timer.value = timer.value - 1 } } else { 
    const currentDay = new Date(timer.value) currentDay.setDate(currentDay.getDate() - 1) // 判断是否小于最小日期 if (currentDay >= minDate) { 
    timer.value = formatDate(currentDay) pickerTime.value = timer.value } } } // 获取后一个月或后一天/后一周的日期 const nextTime = () => { 
    const currentDate = new Date() // 获取当前日期 if (type.value === 'year-month') { 
    const currentMonth = new Date(timer.value + '-01') currentMonth.setMonth(currentMonth.getMonth() + 1) // 判断是否超过当前日期 if (currentMonth <= currentDate) { 
    timer.value = formatMonth(currentMonth) pickerTime.value = timer.value } } else if (type.value === 'week') { 
    const currentWeekStart = new Date(timer.value.split(' - ')[0]) currentWeekStart.setDate(currentWeekStart.getDate() + 7) // 判断是否超过当前日期 if (currentWeekStart <= currentDate) { 
    timer.value = formatWeek(currentWeekStart) pickerTime.value = timer.value.split(' - ') endTime.value = pickerTime.value[1] } } else if (type.value === 'year') { 
    const currentYear = new Date().getFullYear() if (timer.value < currentYear) { 
    timer.value = timer.value + 1 } } else { 
    const currentDay = new Date(timer.value) currentDay.setDate(currentDay.getDate() + 1) // 判断是否超过当前日期 if (currentDay <= currentDate) { 
    timer.value = formatDate(currentDay) pickerTime.value = timer.value } } } const onConfirm = ({ 
     date, selectedValue, selectedOptions }) => { 
    if (type.value === 'year-month') { 
    show.value = false timer.value = formatMonth(new Date(selectedValue)) // 确保 selectedValue 是有效的日期字符串 } else if (type.value === 'date') { 
    show.value = false timer.value = formatDate(new Date(selectedValue)) } pickerTime.value = timer.value // 更新 pickerTime } const onYearConfirm = ({ 
     selectedValue, selectedOptions }) => { 
    timer.value = selectedValue[0] // 更新选中的年份 isPickerVisible.value = false // 关闭选择器 } const closeSwitch = param => { 
    isVisible.value = false } const setChooseValue = param => { 
    let { 
    weekDate } = param pickerTime.value = [weekDate[0].date[3], weekDate[1].date[3]] timer.value = pickerTime.value.join(' - ') } </script> <style lang="scss" scoped> .nut-cell__value { 
    flex: initial; } .time-picker_wrap { 
    width: 100%; height: 100%; box-sizing: border-box; // padding: 24rpx; display: flex; justify-content: space-between; /* Center the elements */ align-items: center; /* Align items vertically */ } .left_btn, .right_btn, .timer_btn { 
    cursor: pointer; padding: 10rpx; /* Add some padding for a better touch target */ } .timer_btn { 
    font-weight: bold; /* Make the time display bold */ } </style> 
使用
//引入组件 //第一层组件已全局注册,不需要局部引入。也可以直接写在这个timePicker文件里面 import timePicker from './time-picker.vue' //第一层筛选tab栏 <tabs-top :tabs='tabsArray' nameKey="label" v-model:value="activeIndex" @change="changeTab" /> //时间选择器 <time-picker :selectTab="selectTab" @changeTime="changeTime" class="piker"></time-picker> //tab栏数据 const tabsArray = [ { 
    label: "日", value: "day", }, { 
    label: "周", value: "week", }, { 
    label: "月", value: "month", }, { 
    label: "年", value: "year", }, ] //默认选中 const activeIndex = ref(0) const selectTab = ref('day') //子传父 const changeTab = ({ 
     value }) => { 
    //父传子 selectTab.value = value } //时间选择器 返回值格式都是数组 ['2024-08-24','2024-08-25'] const changeTime = (value) => { 
    console.log(value) //日 ['2024-08-24','2024-08-24'] //周 ['2024-08-19','2024-08-25'] //月 ['2024-08-01','2024-08-31'] //年 ['2024-01-01','2024-12-31'] //之后拿到值可以做一步操作 ~~~~ } 

ui可以自己改,逻辑直接套用就好~~~

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/117952.html

(0)
上一篇 2025-11-16 22:10
下一篇 2025-11-16 22:20

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信