<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>
当前代码在切换月份后打开picker,picker选中的月份没有选中至切换后的月份
最新发布