移动端年、月、周、日时间选择器(基于Vant+Vue3)

开发移动app项目时,需要选择年、月、周、日下面的具体时间范围,比如年:xxxx年01月01日至xxxx年12月31日;月:当前年加上选择的月份的日期范围;周:当前年的

某一周的时间范围;日期:当前年+当前月份+选择的日期;于是封装了个组件,用的是vant组件库。

先安装组件库依赖

 npm i vant

1.组件封装

tabsDateSelect/index.js

<!-- 时间选择控件 -->
<template>
    <div>
        <van-tabs v-model:active="baseActive" @change="changeActiveName" :swipeable="swipeable">
            <van-tab v-for="(item,index) in tabsOptions" :key="index" :title="item.dictValueName||item.title" :name="item.dictValueCode||item.name">
                <van-tabs v-model:active="item.baseActiveDetail" @change="changeActiveNameDetail" :swipeable="swipeable">
                    <van-tab v-for="(child,cindex) in item.childNodes" :key="cindex" :title="child.dictValueName||child.title" :name="child.dictValueCode||child.name">
                    </van-tab>
                </van-tabs>
            </van-tab>
        </van-tabs>
    </div>

</template>
<script setup>
import { getWeekRange, getMonthDayRange } from '../../utils'
import { ref, reactive, onMounted } from 'vue'
const props = defineProps({
    activeName: {
        type: [Number, String],
        default: '0'
    },
    activeNameDetail: {
        type: [Number, String],
        default: '0'
    },
    swipeable: { // 是否开启手势左右滑动切换
        type: Boolean,
        default: false
    },
    // tabsOptions: {
    //     type: Array,
    //     default: () => {
    //         return []
    //     }
    // },
    tabsOptionsDetail: {
        type: Array,
        default: () => {
            return []
        }
    }
})

onMounted(() => {
    // changeActiveName()
    createdWeek()
})

// 10以下的数 前面补0
const addZero = (val) => {
    return val < 10 ? '0' + val : val
}
// 按月份生成天数
const createdDays = () => {
    const year = new Date().getFullYear()
    const month = new Date().getMonth() + 1 + ''
    const day = new Date().getDate()
    const arr = []
    if (['1', '3', '5', '7', '8', '10', '12'].includes(month)) {
        for (let i = 1; i < 32; i++) {
            arr.push({
                title: i === day ? '今天' : month + '-' + i,
                name: i + '',
                value: year + '-' + addZero(month) + '-' + addZero(i)
            })
        }
    } else if (['4', '6', '9', '11'].includes(month)) {
        for (let i = 1; i < 31; i++) {
            arr.push({
                title: i === day ? '今天' : month + '-' + i,
                name: i + '',
                value: year + '-' + addZero(month) + '-' + addZero(i)
            })
        }
    } else {
        const year = new Date().getFullYear()
        // 平年  29天
        if (year % 4 === 0 && year % 100 !== 0 || year & 400 === 0) {
            for (let i = 1; i < 30; i++) {
                arr.push({
                    title: i === day ? '今天' : month + '-' + i,
                    name: i + '',
                    value: year + '-' + addZero(month) + '-' + addZero(i)
                })
            }
        } else {
            // 闰年 28天
            for (let i = 1; i < 29; i++) {
                arr.push({
                    title: month + '-' + i,
                    name: i + '',
                    value: year + '-' + addZero(month) + '-' + addZero(i)
                })
            }
        }
    }
    return arr
}

// 生成年份
const createdYear = () => {
    const year = new Date().getFullYear()
    const arr = []
    for (let i = year; i > year - 10; i--) {
        arr.push({
            title: i + '年',
            name: '',
            value: '' + (i % year === 0 ? year : i % year)
        })
    }
    arr.reverse()
    arr.forEach((item, index) => {
        item.name = index + ''
    })
    return arr
}

// 当前第几周
const nowWeek = () => {
    const endDate = new Date()
    // 本年的第一天
    const beginDate = new Date(endDate.getFullYear(), 0, 1)
    // 星期从0-6,0代表星期天,6代表星期六
    let endWeek = endDate.getDay()
    if (endWeek == 0) endWeek = 7
    let beginWeek = beginDate.getDay()
    if (beginWeek == 0) beginWeek = 7
    // 计算两个日期的天数差
    var millisDiff = endDate.getTime() - beginDate.getTime()
    var dayDiff = Math.floor((millisDiff + (beginWeek - endWeek) * (24 * 60 * 60 * 1000)) / 86400000)
    return Math.ceil(dayDiff / 7) + 1
}
// 生成周数
const createdWeek = () => {
    const resNum = nowWeek()
    const arr = []
    for (let i = resNum; i > 0; i--) {
        arr.push({
            title: i === resNum ? '本周' : i + 1 === resNum ? '上周' : i + '周',
            name: ''
        })
    }
    arr.reverse()
    arr.forEach((item, index) => {
        item.name = index + 1 + ''
    })
    return arr
}
// 生成月份
const createdMonth = () => {
    const arr = []
    for (let i = 1; i < 13; i++) {
        arr.push({
            title: i + '月',
            name: i + ''
        })
    }
    return arr
}

const tabsOptions = reactive([
    { title: '日', name: 'day', baseActiveDetail: '0', childNodes: createdDays() },
    { title: '周', name: 'week', baseActiveDetail: '0', childNodes: createdWeek() },
    { title: '月', name: 'month', baseActiveDetail: '0', childNodes: createdMonth() },
    { title: '年', name: 'year', baseActiveDetail: '0', childNodes: createdYear() }
])

const emits = defineEmits(['update:activeName', 'changeActive', 'update:activeNameDetail', 'changeActiveDetail'])

const type = ref('')

// 年月日周点击
const changeActiveName = (e, other, other2) => {
    // baseActiveDetail.value = '0' // 设置默认值  根据具体情况具体设置,当天,本月,本年...
    type.value = e
    const obj = { type: e, defaultValue: '' }
    let baseActiveDetail = ''
    if (e === 'day') {
        const dayNow = '' + new Date().getDate()
        tabsOptions.find((item) => { return item.name === 'day' }).baseActiveDetail = other2 || dayNow
        baseActiveDetail = tabsOptions.find((item) => { return item.name === 'day' }).baseActiveDetail
        obj.defaultValue = tabsOptions.find((item) => { return item.name === 'day' }).childNodes[(other2 || dayNow) - 1].name
    } else if (e === 'year') {
        const yearNow = '' + new Date().getFullYear()
        // 获取年份下标
        const nowYearIndex = tabsOptions.find((item) => { return item.name === 'year' }).childNodes.findIndex((item) => { return item.value === yearNow }) + ''
        tabsOptions.find((item) => { return item.name === 'year' }).baseActiveDetail = other2 || nowYearIndex
        baseActiveDetail = tabsOptions.find((item) => { return item.name === 'year' }).baseActiveDetail
        obj.defaultValue = tabsOptions.find((item) => { return item.name === 'year' }).childNodes[other2 || nowYearIndex].value
    } else if (e === 'week') {
        const num = '' + nowWeek()
        tabsOptions.find((item) => { return item.name === 'week' }).baseActiveDetail = other2 || num
        baseActiveDetail = tabsOptions.find((item) => { return item.name === 'week' }).baseActiveDetail
        obj.defaultValue = other2 || num
    } else if (e === 'month') {
        const monthNow = '' + (new Date().getMonth() + 1)
        tabsOptions.find((item) => { return item.name === 'month' }).baseActiveDetail = other2 || monthNow
        baseActiveDetail = tabsOptions.find((item) => { return item.name === 'month' }).baseActiveDetail
        obj.defaultValue = other2 || monthNow
    }
    const timeArr = getTimeByType(obj.type, obj.defaultValue)
    emits('update:activeName', obj)
    emits('changeActive', timeArr, e, baseActiveDetail)
}
// 下排tab点击
const changeActiveNameDetail = (e) => {
    // 判断点击的类型是年
    if (type.value === 'year') {
        const result = tabsOptions.find((item) => { return item.name === 'year' })
        const res = result.childNodes[e].value
        const title = result.childNodes[e].title
        const baseActiveDetail = result.baseActiveDetail
        const timeArr = getTimeByType('year', parseInt(title))
        emits('update:activeNameDetail', res)
        emits('changeActiveDetail', timeArr, baseActiveDetail)
        return
    }
    // 判断点击的类型是日
    if (type.value === 'day') {
        const result = tabsOptions.find((item) => { return item.name === 'day' })
        const res = result.childNodes[e - 1].value
        const baseActiveDetail = result.baseActiveDetail
        const timeArr = getTimeByType('day', e)
        emits('update:activeNameDetail', res)
        emits('changeActiveDetail', timeArr, baseActiveDetail)
        return
    }
    let activeResult = ''
    // 判断点击的类型是周
    if (type.value === 'week') {
        activeResult = tabsOptions.find((item) => { return item.name === 'week' }).baseActiveDetail
    }
    // 判断点击的类型是月
    if (type.value === 'month') {
        activeResult = tabsOptions.find((item) => { return item.name === 'month' }).baseActiveDetail
    }
    const timeRangeArr = getTimeByType(type.value, e)
    emits('update:activeNameDetail', e)
    emits('changeActiveDetail', timeRangeArr, activeResult)
}

const dayNumNow = new Date().getDate()
const baseActive = ref('')

// 根据类型和时间获取时间参数范围   返回值 timeArr 时间数组 []
const getTimeByType = (type, time) => {
    let timeArr = []
    const d = new Date()
    const currentYear = d.getFullYear()
    const currentMonth = d.getMonth() + 1
    const str = currentYear + '-' + currentMonth
    time = time < 10 ? `0${time}` : time
    switch (type) {
        case 'day':
            timeArr = [str + '-' + time, str + '-' + time]
            break
        case 'week':
            timeArr = getWeekRange(currentYear, time)
            break
        case 'month':
            timeArr = getMonthDayRange(currentYear, time)
            break
        case 'year':
            timeArr = getTimeByYear(time)
            break
        default:
            break
    }
    return timeArr
}

// 根据年份获取该年的第一天和最后一天  year 年份
const getTimeByYear = (year) => {
    if (!year) {
        return
    }
    // 该年第一天
    const firstDay = year + '-01-01'
    const lastDay = getMonthDayRange(year, 12)[1]
    return [firstDay, lastDay]
}
// 初始化组件  设置第一排tab和第二排tab的默认值
const init = (a, b) => {
    baseActive.value = a
    if(['day', 'week', 'month', 'year'].includes(a)) {
        tabsOptions.find((item) => { return item.name === a }).baseActiveDetail = b
    }
    changeActiveName(a, '', b)
}
// 暴露init方法  用于父组件调用
defineExpose({ init })
</script>
<style lang="scss">
</style>

utils/index.js

// 通过年份、周数获取日期范围   year 年   weeks 周  getWeekRange(2019,12))--> 2019-03-18~2019-03-24
export function getWeekRange(year, weekNum) {
    const yearStart = new Date(parseInt(year), 0, 1) // 设置该年1.1.
    const firstDay = yearStart.getDay() // 星期
    // 对1.1.所在周的前后几天特殊处理.
    const other = (firstDay >= 0 && firstDay <= 4) ? firstDay - 1 : firstDay - 8

    // 时间调整,得出要计算周的起/始时间.
    // 考虑距离当年1.1.的总天数
    const days = (parseInt(weekNum, 10) - 2) * 7 - other
    // 一天时间的毫秒数
    const oneDay = 24 * 60 * 60 * 1000

    // 当前周 第一天 离1/1/70的毫秒数.
    const dateInMs = oneDay * days + yearStart.getTime()
    // 日期调整(设置1/1/70至今的毫秒数)
    const weekStart = new Date(dateInMs)

    // 当前所选周最后一天处理,同上.
    const dateInMsE = oneDay * 6 + dateInMs
    const weekEnd = new Date(dateInMsE)

    // 月和日的处理,一位变两位,如:1->01.
    let month = weekStart.getMonth() + 1
    month = (month < 10) ? '0' + month : month
    let day = weekStart.getDate()
    day = (day < 10) ? '0' + day : day

    let monthE = weekEnd.getMonth() + 1
    monthE = (monthE < 10) ? '0' + monthE : monthE
    let dayE = weekEnd.getDate()
    dayE = (dayE < 10) ? '0' + dayE : dayE
    return [weekStart.getFullYear() + '-' + month + '-' + day, weekEnd.getFullYear() + '-' + monthE + '-' + dayE]
    // return (month + "-" + day) + "~" + (monthE + "-" + dayE)
}

// 根据年份和月份获取这个月的第一天和最后一天  year 年份   month月份
export function getMonthDayRange(year, month) {
    if (!year || !month) {
        return
    }
    const firstDay = year + '-' + month + '-01'
    const lastDay = new Date(year, month, 0)
    const lastDayYear = lastDay.getFullYear()
    const lastDayMonth = lastDay.getMonth() + 1
    const day = lastDay.getDate()
    return [firstDay, lastDayYear + '-' + lastDayMonth + '-' + day]
}

main.js

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { Tab, Tabs } from 'vant';

const app = createApp(App)
import 'vant/lib/index.css'
app.use(Tab)
app.use(Tabs)
app.mount('#app')

2.组件用法

app.vue

<script setup>
import tabsDateSelect from './components/tabsDateSelect/index.vue'
// 切换日周月年
const changeActive = (res, type, baseActiveDetail) => {
    console.log('切换日周月年=====>', res, type)
}
// 切换日月周年次级tab
const changeActiveDetail = (res, baseActiveDetail) => {
    console.log('切换日月周年次级---------- ', res)
}
</script>

<template>
  <div style="height:200px">
    <tabsDateSelect @changeActive="changeActive" @changeActiveDetail="changeActiveDetail"/>
  </div>
</template>

<style scoped>
</style>

3.效果

  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值