大家好,欢迎来到IT知识分享网。
实现一个时间选择器组件
场景
技术栈(思路都是一样的)
- uniapp + vue3 + nutui
- uniapp + vue3 + uview plus
实现
思路:-自己封装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点的实现之后需要通过组件传值给到这里,用的组件库是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