基于element ui的el-date-picker 日、周、月粒度切换时间选择器

先上效果图

 需求

  • 粒度—时间选择器联动
  • 时间周期不能大于今天。(所以今天以后的时间都不能选)
    • 周粒度——因为一周没过完,所以不能选当前周
    • 月粒度——因为本月没结束,不能选当前月
  • 切换粒度的时候自动选择最近符合的时间。
  • 侧边有快捷选择。

根据需求还有个隐藏bug 周需要特殊处理选择的日期还有样式

周粒度是一周一周选择,所以需要特殊处理

上代码

父组件使用

<lidu-picker ref="liduPicker" @changeDate="changeDate"></lidu-picker>

import liduPicker from './components/liduPicker'
monted(){
  // 默认日粒度 可以父组件调用初始化也可以直接在子组件初始化
  // this.$refs['liduPicker'].changeSize(1)
}

组件liduPicker 周粒度的时候需要增加class="is-week-mode"

date-picker的 value-format="yyyy-MM-dd",其他的未测试是否有影响

组件内在最后使用了dateFormat处理时间。没有的请修改

<template>
    <el-form inline size="medium">
        <el-form-item>
            <el-select v-model="lidu" placeholder="请选择" @change="changeSize">
                <el-option label="日粒度" :value="1"></el-option>
                <el-option label="周粒度" :value="2"></el-option>
                <el-option label="月粒度" :value="3"></el-option>
            </el-select>
        </el-form-item>
        <el-form-item>
            <el-date-picker
                style="300px"
                v-model="datePicker"
                :type="lidu == 3 ? 'monthrange' : 'daterange'"
                align="left"
                unlink-panels
                range-separator="至"
                start-placeholder="开始时间"
                end-placeholder="结束时间"
                :picker-options="pickerOptions"
                value-format="yyyy-MM-dd"
                @change="changeDate"
                @focus="setWeekClass"
            ></el-date-picker>
        </el-form-item>
    </el-form>
</template>

<script>
import { dateFormat } from '@/helpers/utils'

export default {
    data() {
        return {
            // 粒度 1:日,2:周,3:月
            lidu: 1,
            // 时间区间选择
            datePicker: [],
            pickerOptions: {
                firstDayOfWeek: 1,
                shortcuts: [],
            },
        }
    },
    methods: {
        // 切换粒度
        changeSize(val) {
            this.datePicker = []
            let shortcuts = []
            // 一天时间
            const day = 3600 * 1000 * 24
            const date = new Date()
            const end = date - day
            // 日粒度
            if (val == 1) {
                //   初始化时间 默认最近7天
                this.changeDate([date - day * 7, date - day])
                //   昨日
                const latelyDay = this.setShortcut('昨日', end, end)
                //   上周
                const curDay = date.getDay()
                const lastWeek = this.setShortcut('上周', date - day * (7 + curDay), date - day * (1 + curDay))
                //   本月
                const curMonth = this.setShortcut('本月', new Date().setDate(1), end)
                //   上月  上个月第一天 ~ 上个月最后一天
                const lastMonth = this.setShortcut('上月', new Date(date.getFullYear(), date.getMonth(), 0).setDate(1), new Date().setDate(0))
                //   最近一周
                const latelyWeek = this.setShortcut('最近7天', date - day * 7, end)
                //   最近15天
                const latelyHalfMonth = this.setShortcut('最近15天', date - day * 15, end)
                //   最近30天
                const latelyMonth = this.setShortcut('最近30天', date - day * 31, end)
                //   最近90天
                const lately3Month = this.setShortcut('最近90天', date - day * 91, end)
                shortcuts.push(latelyDay, lastWeek, curMonth, lastMonth, latelyWeek, latelyHalfMonth, latelyMonth, lately3Month)
                // 选择限制 不能选今天以后
                this.pickerOptions.disabledDate = time => {
                    return time.getTime() + 86400000 >= Date.now()
                }
            }
            // 周粒度
            if (val == 2) {
                //   初始化时间 默认最近7天
                this.changeDate([date - day * 7, date - day])
                //   最近7天
                const latelyWeek = this.setShortcut('最近7天', date - day * 7, end)
                // 最近30天
                const latelyMonth = this.setShortcut('最近30天', date - day * 31, end)
                // 最近90天
                const lately3Month = this.setShortcut('最近90天', date - day * 91, end)
                shortcuts.push(latelyWeek, latelyMonth, lately3Month)
                // 选择限制 不能选今天以后
                this.pickerOptions.disabledDate = time => {
                    return time.getTime() + 86400000 >= Date.now()
                }
            }
            // 月粒度 都是到上个月的最后一天
            if (val == 3) {
                const lastMonth1 = new Date(date.getFullYear(), date.getMonth(), 0).setDate(1)
                // 初始化时间 默认上月
                this.changeDate([lastMonth1, lastMonth1])
                // 上月
                const last1M = this.setShortcut('上月', lastMonth1, lastMonth1)
                // 今年
                const curYear = this.setShortcut('今年', new Date(date.getFullYear(), 0), lastMonth1)
                // 最近三个月
                const last3M = this.setShortcut('最近三个月', new Date(date.getFullYear(), date.getMonth() - 3), lastMonth1)
                // 最近六个月
                const last6M = this.setShortcut('最近六个月', new Date(date.getFullYear(), date.getMonth() - 6), lastMonth1)
                shortcuts.push(last1M, curYear, last3M, last6M)
                // 选择限制 不能选上个月最后一天之后
                this.pickerOptions.disabledDate = time => {
                    return time.getTime() + 86400000 >= new Date().setDate(0)
                }
            }
            // console.log('快捷设置:', shortcuts)
            this.pickerOptions.shortcuts = shortcuts
        },
        setShortcut(text, start, end) {
            return {
                text,
                onClick(picker) {
                    picker.$emit('pick', [dateFormat(new Date(start), 'YYYY-MM-dd'), dateFormat(new Date(end), 'YYYY-MM-dd')])
                },
            }
        },
        // 所选时间
        changeDate(date) {
            if (!date) return
            // 日粒度
            if (this.lidu == 1) {
                date = [dateFormat(new Date(date[0]), 'YYYY-MM-dd'), dateFormat(new Date(date[1]), 'YYYY-MM-dd')]
                this.datePicker = this.datePicker.length ? this.datePicker : date
            }
            // 周粒度
            if (this.lidu == 2) {
                // 取出开始时间和结束时间分别是周几
                const day = 3600 * 1000 * 24
                const yesterday = new Date() - day
                const start = new Date(date[0])
                const end = new Date(date[1])
                // 开始时间是距离周一天数
                const startDay = start.getDay() == 0 ? 6 : start.getDay() - 1
                // 结束时间是距离周日天数
                const endDay = end.getDay() == 0 ? 6 : end.getDay() - 1
                // 距离上周一天数
                const monDay = 13 - new Date().getDay()
                const lastMonday = new Date() - day * monDay
                // 距离上周日天数
                const sunDay = new Date().getDay() == 0 ? 7 : new Date().getDay()
                const lastSunday = new Date() - day * sunDay
                const res = []
                // 计算所选开始时间的周一  (判断当前所选日期的周一是否 > 上周一)
                res[0] = Number(start) - day * startDay > Number(lastMonday) ? Number(lastMonday) : Number(start) - day * startDay
                // 计算所选结束时间的周日   (判断当前所选日期的周日是否 > 上周日)
                res[1] = Number(end) + day * (6 - endDay) > Number(lastSunday) ? Number(lastSunday) : Number(end) + day * (6 - endDay)
                this.datePicker = [dateFormat(new Date(res[0]), 'YYYY-MM-dd'), dateFormat(new Date(res[1]), 'YYYY-MM-dd')]
            }
            // 月粒度
            if (this.lidu == 3) {
                const endTime = new Date(date[1])
                endTime.setMonth(endTime.getMonth() + 1)
                const endDay = endTime.setDate(0)
                // console.log('结束时间的月底', dateFormat(new Date(endDay), 'YYYY-MM-dd'))
                this.datePicker = [dateFormat(new Date(date[0]), 'YYYY-MM-dd'), dateFormat(new Date(endDay), 'YYYY-MM-dd')]
            }
            // console.log('this.datePicker',this.datePicker)
            this.$emit('changeDate', this.lidu, this.datePicker)
        },
        // 如果是周粒度的时候 首次进入需要绑定样式 is-week-mode
        setWeekClass(event) {
            if (this.lidu == 2 && event.picker && event.picker.$children[0].$el.className != 'el-date-table is-week-mode') {
                // console.log(event.picker)
                event.picker.$children.forEach(r => {
                    //   console.log(r.$el)
                    r.$el.className = `el-date-table is-week-mode`
                })
            } else if (this.lidu != 2 && event.picker && event.picker.$children[0].$el.className == 'el-date-table is-week-mode') {
                event.picker.$children.forEach(r => {
                    //   console.log(r.$el)
                    r.$el.className = `el-date-table`
                })
            }
        },
    },
    mounted() {
        // 默认日粒度
        this.changeSize(1)
    },
}
</script>

<style></style>
<template>
    <el-form inline size="medium">
        <el-form-item>
            <el-select v-model="lidu" placeholder="请选择" @change="changeSize">
                <el-option label="日粒度" :value="1"></el-option>
                <el-option label="周粒度" :value="2"></el-option>
                <el-option label="月粒度" :value="3"></el-option>
            </el-select>
        </el-form-item>
        <el-form-item>
            <el-date-picker
                style="300px"
                v-model="datePicker"
                :type="lidu == 3 ? 'monthrange' : 'daterange'"
                align="left"
                unlink-panels
                range-separator=""
                start-placeholder="开始时间"
                end-placeholder="结束时间"
                :picker-options="pickerOptions"
                value-format="yyyy-MM-dd"
                @change="changeDate"
                @focus="setWeekClass"
            ></el-date-picker>
        </el-form-item>
    </el-form>
</template>

<script>
import { dateFormat } from '@/helpers/utils'

export default {
    data() {
        return {
            // 粒度 1:日,2:周,3:月
            lidu: 1,
            // 时间区间选择
            datePicker: [],
            pickerOptions: {
                firstDayOfWeek: 1,
                shortcuts: [],
            },
        }
    },
    methods: {
        // 切换粒度
        changeSize(val) {
            this.datePicker = []
            let shortcuts = []
            // 一天时间
            const day = 3600 * 1000 * 24
            const date = new Date()
            const end = date - day
            // 日粒度
            if (val == 1) {
                //   初始化时间 默认最近7天
                this.changeDate([date - day * 7, date - day])
                //   昨日
                const latelyDay = this.setShortcut('昨日', end, end)
                //   上周
                const curDay = date.getDay()
                const lastWeek = this.setShortcut('上周', date - day * (7 + curDay), date - day * (1 + curDay))
                //   本月
                const curMonth = this.setShortcut('本月', new Date().setDate(1), end)
                //   上月  上个月第一天 ~ 上个月最后一天
                const lastMonth = this.setShortcut('上月', new Date(date.getFullYear(), date.getMonth(), 0).setDate(1), new Date().setDate(0))
                //   最近一周
                const latelyWeek = this.setShortcut('最近7天', date - day * 7, end)
                //   最近15天
                const latelyHalfMonth = this.setShortcut('最近15天', date - day * 15, end)
                //   最近30天
                const latelyMonth = this.setShortcut('最近30天', date - day * 31, end)
                //   最近90天
                const lately3Month = this.setShortcut('最近90天', date - day * 91, end)
                shortcuts.push(latelyDay, lastWeek, curMonth, lastMonth, latelyWeek, latelyHalfMonth, latelyMonth, lately3Month)
                // 选择限制 不能选今天以后
                this.pickerOptions.disabledDate = time => {
                    return time.getTime() + 86400000 >= Date.now()
                }
            }
            // 周粒度
            if (val == 2) {
                //   初始化时间 默认最近7天
                this.changeDate([date - day * 7, date - day])
                //   最近7天
                const latelyWeek = this.setShortcut('最近7天', date - day * 7, end)
                // 最近30天
                const latelyMonth = this.setShortcut('最近30天', date - day * 31, end)
                // 最近90天
                const lately3Month = this.setShortcut('最近90天', date - day * 91, end)
                shortcuts.push(latelyWeek, latelyMonth, lately3Month)
                // 选择限制 不能选今天以后
                this.pickerOptions.disabledDate = time => {
                    return time.getTime() + 86400000 >= Date.now()
                }
            }
            // 月粒度 都是到上个月的最后一天
            if (val == 3) {
                const lastMonth1 = new Date(date.getFullYear(), date.getMonth(), 0).setDate(1)
                // 初始化时间 默认上月
                this.changeDate([lastMonth1, lastMonth1])
                // 上月
                const last1M = this.setShortcut('上月', lastMonth1, lastMonth1)
                // 今年
                const curYear = this.setShortcut('今年', new Date(date.getFullYear(), 0), lastMonth1)
                // 最近三个月
                const last3M = this.setShortcut('最近三个月', new Date(date.getFullYear(), date.getMonth() - 3), lastMonth1)
                // 最近六个月
                const last6M = this.setShortcut('最近六个月', new Date(date.getFullYear(), date.getMonth() - 6), lastMonth1)
                shortcuts.push(last1M, curYear, last3M, last6M)
                // 选择限制 不能选上个月最后一天之后
                this.pickerOptions.disabledDate = time => {
                    return time.getTime() + 86400000 >= new Date().setDate(0)
                }
            }
            // console.log('快捷设置:', shortcuts)
            this.pickerOptions.shortcuts = shortcuts
        },
        setShortcut(text, start, end) {
            return {
                text,
                onClick(picker) {
                    picker.$emit('pick', [dateFormat(new Date(start), 'YYYY-MM-dd'), dateFormat(new Date(end), 'YYYY-MM-dd')])
                },
            }
        },
        // 所选时间
        changeDate(date) {
            if (!date) return
            if (this.lidu == 1) {
                date = [dateFormat(new Date(date[0]), 'YYYY-MM-dd'), dateFormat(new Date(date[1]), 'YYYY-MM-dd')]
                this.datePicker = this.datePicker.length ? this.datePicker : date
            }
            if (this.lidu == 2) {
                // 取出开始时间和结束时间分别是周几
                const day = 3600 * 1000 * 24
                const yesterday = new Date() - day
                const start = new Date(date[0])
                const end = new Date(date[1])
                // 开始时间是距离周一天数
                const startDay = start.getDay() == 0 ? 6 : start.getDay() - 1
                // 结束时间是距离周日天数
                const endDay = end.getDay() == 0 ? 6 : end.getDay() - 1
                // 距离上周一天数
                const monDay = 13 - new Date().getDay()
                const lastMonday = new Date() - day * monDay
                // 距离上周日天数
                const sunDay = new Date().getDay() == 0 ? 7 : new Date().getDay()
                const lastSunday = new Date() - day * sunDay
                const res = []
                // 计算所选开始时间的周一  (判断当前所选日期的周一是否 > 上周一)
                res[0] = Number(start) - day * startDay > Number(lastMonday) ? Number(lastMonday) : Number(start) - day * startDay
                // 计算所选结束时间的周日   (判断当前所选日期的周日是否 > 上周日)
                res[1] = Number(end) + day * (6 - endDay) > Number(lastSunday) ? Number(lastSunday) : Number(end) + day * (6 - endDay)
                this.datePicker = [dateFormat(new Date(res[0]), 'YYYY-MM-dd'), dateFormat(new Date(res[1]), 'YYYY-MM-dd')]
            }
            if (this.lidu == 3) {
                const endTime = new Date(date[1])
                endTime.setMonth(endTime.getMonth() + 1)
                const endDay = endTime.setDate(0)
                // console.log('结束时间的月底', dateFormat(new Date(endDay), 'YYYY-MM-dd'))
                this.datePicker = [dateFormat(new Date(date[0]), 'YYYY-MM-dd'), dateFormat(new Date(endDay), 'YYYY-MM-dd')]
            }
            // console.log('this.datePicker',this.datePicker)
            this.$emit('changeDate', this.lidu, this.datePicker)
        },
        // 如果是周粒度的时候 首次进入需要绑定样式 is-week-mode
        setWeekClass(event) {
            if (this.lidu == 2 && event.picker && event.picker.$children[0].$el.className != 'el-date-table is-week-mode') {
                // console.log(event.picker)
                event.picker.$children.forEach(r => {
                    //   console.log(r.$el)
                    r.$el.className = `el-date-table is-week-mode`
                })
            } else if (this.lidu != 2 && event.picker && event.picker.$children[0].$el.className == 'el-date-table is-week-mode') {
                event.picker.$children.forEach(r => {
                    //   console.log(r.$el)
                    r.$el.className = `el-date-table`
                })
            }
        },
    },
    mounted() {
        // 默认日粒度
        this.changeSize(1)
    },
}
</script>

<style></style>
原文地址:https://www.cnblogs.com/HDWdemo/p/14682167.html