next-date-picker日历选择 日期多选 日期单选 自定义日历组件

https://ext.dcloud.net.cn/plugin?id=12562
日期选择组件

有四种模式:

简单的年月日弹窗选择(mode=“simple”)
日历弹窗选择多个日期(多选)(mode=“multiple”)
日历弹窗选择单个日期(单选)(mode=“single”)
日历弹窗选择区间日期(区间)(mode=“range”)

在这里插入图片描述
示例代码vue3

<template>
    <view>
        <next-date-picker 
            ref="nextDatePickerRef" 
            :mode="mode"
            :isAbleSelectFutureDate="false"
            :defaultDate="dateModel"
            @finishSelectDate="finishSelectDate" 
            :defaultCheckedList="[]">
        </next-date-picker>

        <view style="margin-top: 48rpx;">
            <view @click="show('simple')" class="btn">简单选择模式</view>
            <view @click="show('range')" class="btn">日历区间模式</view>
            <view @click="show('multiple')" class="btn">日历多选模式</view>
            <view @click="show('single')" class="btn">日历单选模式</view>
        </view> 
    </view>
</template>

<script>
    import {ref, unref} from 'vue'
    export default {
        setup() {
            const mode = ref('simple');
            const nextDatePickerRef = ref();
            function show(showType) {
                mode.value = showType;
                nextDatePickerRef.value.open();
            }
            function finishSelectDate(e) {
                console.log("选择了日期:",e);
            }
            const dateModel = ref('2023-5-11')
            return {
                mode,
                show,
                finishSelectDate,
                nextDatePickerRef,
                dateModel
            }
        }
    }
</script>

<style lang="scss">
.btn{
    width: 600rpx;
    margin-left: 74rpx;
    margin-right: 74rpx;
    text-align: center;
    padding: 12rpx;
    background-color: #e49a30;
    color: aliceblue;
    border-radius: 12rpx;
    margin-top: 24rpx;
}
</style>
<template> <view :class="{ 'zy-uni-calendar': isShowAllways, 'zy-uni-calendar-flot': !isShowAllways, 'zy-uni-calendar__content-mobile': aniMaskShow }" :style="zyUniCalendarFlot" @mouseleave="leaveCale" > <view v-if="!insert && show" class="zy-uni-calendar__mask" :class="{ 'zy-uni-calendar--mask-show': aniMaskShow }" @click="maskClick" ></view> <!-- 头部插槽 --> <slot name="calender-header-slot"></slot> <view v-if="show || isShowAllways" class="zy-uni-calendar__content" :class="{ 'zy-uni-calendar--fixed': !insert, 'zy-uni-calendar--ani-show': aniMaskShow, 'zy-uni-calendar__content-mobile': aniMaskShow }" > <view class="zy-uni-calendar__box"> <view v-if="showMonth" class="zy-uni-calendar__box-bg"> <text class="zy-uni-calendar__box-bg-text">{{ nowDate.month }}</text> </view> <!-- 头部星期代码 --> <view class="zy-uni-calendar__weeks zy-uni-calendar__weeks_header" :style="zyUniCalendarFlotWeeksHeader"> <view class="zy-uni-calendar__weeks-day"> <text class="zy-uni-calendar__weeks-day-text">{{ SUNText }}</text> </view> <view class="zy-uni-calendar__weeks-day"> <text class="zy-uni-calendar__weeks-day-text">{{ MONText }}</text> </view> <view class="zy-uni-calendar__weeks-day"> <text class="zy-uni-calendar__weeks-day-text">{{ TUEText }}</text> </view> <view class="zy-uni-calendar__weeks-day"> <text class="zy-uni-calendar__weeks-day-text">{{ WEDText }}</text> </view> <view class="zy-uni-calendar__weeks-day"> <text class="zy-uni-calendar__weeks-day-text">{{ THUText }}</text> </view> <view class="zy-uni-calendar__weeks-day"> <text class="zy-uni-calendar__weeks-day-text">{{ FRIText }}</text> </view> <view class="zy-uni-calendar__weeks-day"> <text class="zy-uni-calendar__weeks-day-text">{{ SATText }}</text> </view> </view> <!-- 回显年月与左右切换代码 --> <view class="zy-uni-calendar__header" :style="zyUniCalendarFlotWeeksContent" :class="{ 'zy-uni-calendar__header-mobile': !insert }" > <picker mode="date" :value="date" fields="month" @change="bindDateChange"> <view class="zy-uni-calendar__header-date-box"> <text class="zy-uni-calendar__header-text">{{ (nowDate.year || '') + yearText + (nowDate.month || '') + monthText }}</text> <view class="zy-uni-calendar__header-btn-box"> <view class="zy-uni-calendar__header-btn-one zy-uni-calendar--right"></view> </view> </view> </picker> <view class="zy-uni-calendar__header-btn-big-box"> <view class="zy-uni-calendar__header-btn-box" @click.stop="changeMonth('pre')"> <view class="zy-uni-calendar__header-btn zy-uni-calendar--left"></view> </view> <view class="zy-uni-calendar__header-btn-box" @click.stop="changeMonth('next')"> <view class="zy-uni-calendar__header-btn zy-uni-calendar--right"></view> </view> </view> <!-- 右侧关闭代码 --> <!-- <view v-if="!insert" class="dialog-close" @click="maskClick"> <view class="dialog-close-plus" data-id="close"></view> <view class="dialog-close-plus dialog-close-rotate" data-id="close"></view> </view> --> </view> <view class="zy-uni-calendar__weeks" v-for="(item, weekIndex) in weeks" :key="weekIndex" :style="zyUniCalendarFlotWeeks" > <view class="zy-uni-calendar__weeks-item" v-for="(weeks, weeksIndex) in item" :key="weeksIndex"> <calendar-item class="zy-uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected" :checkHover="range" @change="choiceDate" @handleMouse="handleMouse" :zyUniCalendarFlotItemWeeksBoxItem="zyUniCalendarFlotItemWeeksBoxItem" > </calendar-item> </view> </view> </view> <view v-if="!insert && !range && hasTime" class="uni-date-changed zy-uni-calendar--fixed-top" style="padding: 0 80px" > <view class="uni-date-changed--time-date">{{ tempSingleDate ? tempSingleDate : selectDateText }}</view> <time-picker type="time" :start="timepickerStartTime" :end="timepickerEndTime" v-model="time" :disabled="!tempSingleDate" :border="false" :hide-second="hideSecond" class="time-picker-style" > </time-picker> </view> <view v-if="!insert && range && hasTime" class="uni-date-changed zy-uni-calendar--fixed-top"> <view class="uni-date-changed--time-start"> <view class="uni-date-changed--time-date">{{ tempRange.before ? tempRange.before : startDateText }} </view> <time-picker type="time" :start="timepickerStartTime" v-model="timeRange.startTime" :border="false" :hide-second="hideSecond" :disabled="!tempRange.before" class="time-picker-style" > </time-picker> </view> <view style="line-height: 50px"> <uni-icons type="arrowthinright" color="#999"></uni-icons> </view> <view class="uni-date-changed--time-end"> <view class="uni-date-changed--time-date">{{ tempRange.after ? tempRange.after : endDateText }}</view> <time-picker type="time" :end="timepickerEndTime" v-model="timeRange.endTime" :border="false" :hide-second="hideSecond" :disabled="!tempRange.after" class="time-picker-style" > </time-picker> </view> </view> <!-- 确认按钮代码 --> <view v-if="!insert" class="uni-date-changed uni-date-btn--ok"> <view class="uni-datetime-picker--btn" @click="confirm">{{ confirmText }}</view> </view> </view> <!-- 脚部插槽 --> <slot name="calender-footer-slot" :tempRange="tempRange" :clearData="clearCalender"></slot> </view> </template> <script> import { Calendar, getDate, getTime } from './util.js' import calendarItem from './calendar-item.vue' import timePicker from './time-picker.vue' import { initVueI18n } from '@dcloudio/uni-i18n' import i18nMessages from './i18n/index.js' const { t } = initVueI18n(i18nMessages) /** * Calendar 日历 * @description 日历组件可以查看日期选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等 * @tutorial https://ext.dcloud.net.cn/plugin?id=56 * @property {String} date 自定义当前时间,默认为今天 * @property {String} startDate 日期选择范围-开始日期 * @property {String} endDate 日期选择范围-结束日期 * @property {Boolean} range 范围选择 * @property {Boolean} insert = [true|false] 插入模式,默认为true * @value true 弹窗模式 * @value false 插入模式 * @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容 * @property {Array} selected 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}] * @property {Boolean} showMonth 是否选择月份为背景 * @property {[String} defaultValue 选择器打开时默认显示的时间 * @event {Function} change 日期改变,`insert :ture` 时生效 * @event {Function} confirm 确认选择`insert :false` 时生效 * @event {Function} monthSwitch 切换月份时触发 * @example <zy-uni-calendar :insert="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" /> */ export default { components: { calendarItem, timePicker }, options: { // #ifdef MP-TOUTIAO // virtualHost: false, // #endif // #ifndef MP-TOUTIAO // virtualHost: true // #endif }, props: { date: { type: String, default: '' }, defTime: { type: [String, Object], default: '' }, selectableTimes: { type: [Object], default() { return {} } }, selected: { type: Array, default() { return [] } }, startDate: { type: String, default: '' }, endDate: { type: String, default: '' }, startPlaceholder: { type: String, default: '' }, endPlaceholder: { type: String, default: '' }, range: { type: Boolean, default: false }, hasTime: { type: Boolean, default: false }, insert: { type: Boolean, default: true }, showMonth: { type: Boolean, default: false }, clearDate: { type: Boolean, default: true }, checkHover: { type: Boolean, default: true }, hideSecond: { type: [Boolean], default: false }, pleStatus: { type: Object, default() { return { before: '', after: '', data: [], fulldate: '' } } }, defaultValue: { type: [String, Object, Array], default: '' }, type: { type: String, default: 'date' }, changeClose: { type: [Boolean], default: false }, isShowAllways: { type: [Boolean], default: false }, zyUniCalendarFlot: { type: Object, default: () => ({}) }, zyUniCalendarFlotWeeks: { type: Object, default: () => ({}) }, zyUniCalendarFlotWeeksHeader: { type: Object, default: () => ({}) }, zyUniCalendarFlotWeeksContent: { type: Object, default: () => ({}) }, zyUniCalendarFlotItemWeeksBoxItem: { type: Object, default: () => ({}) }, selectOtherMonth: { type: [Boolean], default: false }, isNeedCheck: { type: [Boolean], default: false } }, data() { return { show: false, weeks: [], calendar: {}, nowDate: {}, aniMaskShow: false, firstEnter: true, time: '', timeRange: { startTime: '', endTime: '' }, tempSingleDate: '', tempRange: { before: '', after: '' } } }, watch: { date: { immediate: true, handler(newVal) { if (!this.range) { this.tempSingleDate = newVal setTimeout(() => { this.init(newVal) }, 100) } } }, defTime: { immediate: true, handler(newVal) { if (!this.range) { this.time = newVal } else { this.timeRange.startTime = newVal.start this.timeRange.endTime = newVal.end } } }, startDate(val) { // 字节小程序 watch 早于 created if (!this.cale) { return } this.cale.setStartDate(val) this.cale.setDate(this.nowDate.fullDate) this.weeks = this.cale.weeks }, endDate(val) { // 字节小程序 watch 早于 created if (!this.cale) { return } this.cale.setEndDate(val) this.cale.setDate(this.nowDate.fullDate) this.weeks = this.cale.weeks }, selected(newVal) { // 字节小程序 watch 早于 created if (!this.cale) { return } this.cale.setSelectInfo(this.nowDate.fullDate, newVal) this.weeks = this.cale.weeks }, pleStatus: { immediate: true, handler(newVal) { const { before, after, fulldate, which } = newVal this.tempRange.before = before this.tempRange.after = after setTimeout(() => { if (fulldate) { this.cale.setHoverMultiple(fulldate) if (before && after) { this.cale.lastHover = true if (this.rangeWithinMonth(after, before)) return this.setDate(before) } else { this.cale.setMultiple(fulldate) this.setDate(this.nowDate.fullDate) this.calendar.fullDate = '' this.cale.lastHover = false } } else { // 字节小程序 watch 早于 created if (!this.cale) { return } this.cale.setDefaultMultiple(before, after) if (which === 'left' && before) { this.setDate(before) this.weeks = this.cale.weeks } else if (after) { this.setDate(after) this.weeks = this.cale.weeks } this.cale.lastHover = true } }, 16) } } }, computed: { timepickerStartTime() { const activeDate = this.range ? this.tempRange.before : this.calendar.fullDate return activeDate === this.startDate ? this.selectableTimes.start : '' }, timepickerEndTime() { const activeDate = this.range ? this.tempRange.after : this.calendar.fullDate return activeDate === this.endDate ? this.selectableTimes.end : '' }, /** * for i18n */ selectDateText() { return t('uni-datetime-picker.selectDate') }, startDateText() { return this.startPlaceholder || t('uni-datetime-picker.startDate') }, endDateText() { return this.endPlaceholder || t('uni-datetime-picker.endDate') }, okText() { return t('uni-datetime-picker.ok') }, yearText() { return t('uni-datetime-picker.year') }, monthText() { return t('uni-datetime-picker.month') }, MONText() { return t('uni-calender.MON') }, TUEText() { return t('uni-calender.TUE') }, WEDText() { return t('uni-calender.WED') }, THUText() { return t('uni-calender.THU') }, FRIText() { return t('uni-calender.FRI') }, SATText() { return t('uni-calender.SAT') }, SUNText() { return t('uni-calender.SUN') }, confirmText() { return t('uni-calender.confirm') } }, created() { // 获取日历方法实例 this.cale = new Calendar({ selected: this.selected, startDate: this.startDate, endDate: this.endDate, range: this.range, selectOtherMonth: this.selectOtherMonth }) // 中某一天 this.init(this.date) }, methods: { leaveCale() { this.firstEnter = true }, handleMouse(weeks) { this.confirm() if (weeks.disable) return if (this.cale.lastHover) return let { before } = this.cale.multipleStatus if (!before) return this.calendar = weeks // 设置范围 this.cale.setHoverMultiple(this.calendar.fullDate) this.weeks = this.cale.weeks // hover时,进入一个日历,更新另一个 if (this.firstEnter) { this.$emit('firstEnterCale', this.cale.multipleStatus) this.firstEnter = false } }, rangeWithinMonth(A, B) { const [yearA, monthA] = A.split('-') const [yearB, monthB] = B.split('-') return yearA === yearB && monthA === monthB }, // 蒙版点击事件 maskClick() { this.close() this.$emit('maskClose') }, clearCalender() { if (this.range) { this.timeRange.startTime = '' this.timeRange.endTime = '' this.tempRange.before = '' this.tempRange.after = '' this.cale.multipleStatus.before = '' this.cale.multipleStatus.after = '' this.cale.multipleStatus.data = [] this.cale.lastHover = false } else { this.time = '' this.tempSingleDate = '' } this.calendar.fullDate = '' this.setDate(new Date()) }, bindDateChange(e) { const value = e.detail.value + '-1' this.setDate(value) }, /** * 初始化日期显示 * @param {Object} date */ init(date) { // 字节小程序 watch 早于 created if (!this.cale) { return } this.cale.setDate(date || new Date()) this.weeks = this.cale.weeks this.nowDate = this.cale.getInfo(date) this.calendar = { ...this.nowDate } if (!date) { // 优化date为空默认不中今天 this.calendar.fullDate = '' if (this.defaultValue && !this.range) { // 暂时只支持移动端非范围选择 const defaultDate = new Date(this.defaultValue) const fullDate = getDate(defaultDate) const year = defaultDate.getFullYear() const month = defaultDate.getMonth() + 1 const date = defaultDate.getDate() const day = defaultDate.getDay() this.calendar = { fullDate, year, month, date, day } this.tempSingleDate = fullDate this.time = getTime(defaultDate, this.hideSecond) } } }, /** * 打开日历弹窗 */ open() { // 弹窗模式并且清理数据 if (this.clearDate && !this.insert) { this.cale.cleanMultipleStatus() this.init(this.date) } this.show = true this.$nextTick(() => { setTimeout(() => { this.aniMaskShow = true }, 50) }) }, /** * 关闭日历弹窗 */ close() { this.aniMaskShow = false this.$nextTick(() => { setTimeout(() => { this.show = false this.$emit('close') }, 50) }) }, /** * 确认按钮 */ confirm() { this.setEmit('confirm') this.close() }, /** * 变化触发 */ change(isSingleChange) { // console.log('🚀 ~ change ~ isSingleChange:', isSingleChange) // if (!this.insert && !isSingleChange) return if (!isSingleChange) return this.setEmit('change') // 单选时直接返回值并关闭弹窗 if (this.changeClose) { this.confirm() } if (this.isShowAllways) { this.setEmit('confirm') } }, /** * 选择月份触发 */ monthSwitch() { let { year, month } = this.nowDate this.$emit('monthSwitch', { year, month: Number(month) }) }, /** * 派发事件 * @param {Object} name */ setEmit(name) { if (!this.range) { if (!this.calendar.fullDate) { this.calendar = this.cale.getInfo(new Date()) this.tempSingleDate = this.calendar.fullDate } if (this.hasTime && !this.time) { this.time = getTime(new Date(), this.hideSecond) } } let { year, month, date, fullDate, extraInfo } = this.calendar this.$emit(name, { range: this.cale.multipleStatus, year, month, date, time: this.time, timeRange: this.timeRange, fulldate: fullDate, extraInfo: extraInfo || {} }) }, /** * 选择天触发 * @param {Object} weeks */ choiceDate(weeks) { if (weeks.disable) return this.calendar = weeks this.calendar.userChecked = true let obj = { ...this.cale.multipleStatus } let isFirstTime = true // console.log('🚀 ~ choiceDate ~ obj:', obj) if (this.changeClose && this.type == 'daterange') { if (!obj.after && !obj.before) { obj.after = weeks.fullDate } if (!obj.after) { isFirstTime = false } } if (!obj.after && !obj.before) { obj.after = weeks.fullDate } if (!obj.after) { isFirstTime = false } if (this.isNeedCheck && this.type == 'daterange') { this.$emit('itemCheck', weeks.fullDate, isFirstTime) } // 设置 this.cale.setMultiple(this.calendar.fullDate, weeks.beforeMonth ?? false, weeks.afterMonth ?? false) this.weeks = this.cale.weeks this.tempSingleDate = this.calendar.fullDate const beforeDate = new Date(this.cale.multipleStatus.before).getTime() const afterDate = new Date(this.cale.multipleStatus.after).getTime() if (beforeDate > afterDate && afterDate) { this.tempRange.before = this.cale.multipleStatus.after this.tempRange.after = this.cale.multipleStatus.before } else { this.tempRange.before = this.cale.multipleStatus.before this.tempRange.after = this.cale.multipleStatus.after } if (this.isShowAllways) { if (this.type == 'date') { this.change(true) } else { if (!isFirstTime) { this.change(true) } else { this.change(false) } } } if (this.changeClose) { if (this.type == 'date') { this.change(true) } else if (!isFirstTime) { this.change(true) } } }, changeMonth(type) { let newDate if (type === 'pre') { newDate = this.cale.getPreMonthObj(this.nowDate.fullDate).fullDate } else if (type === 'next') { newDate = this.cale.getNextMonthObj(this.nowDate.fullDate).fullDate } this.setDate(newDate) this.monthSwitch() }, /** * 设置日期 * @param {Object} date */ setDate(date) { this.cale.setDate(date) this.weeks = this.cale.weeks this.nowDate = this.cale.getInfo(date) } } } </script> 当前代码在切换月份后打开pickerpicker中的月份没有中至切换后的月份
最新发布
08-15
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值