场景
使用vue2+vant UI 开发H5页面,需要用到日历组件选开始日期和结束日期
问题
<van-calendar
type="range"
color="#1989fa"
confirm-text="完成选择"
confirm-disabled-text="请选择结束时间"
v-model="isShowRange"
:min-date="minDate"
:max-date="maxDate"
@confirm="confirmDate"
@closed="cancelData"
/>
vant的calendar组件,没有‘上一年’,‘上一月’,‘下一年’,‘下一月’的快捷按钮,
如果需要选择2001-01-01 到 2024-12-31,需要一直往上翻,然后再一直往下翻,
对用户来说,很不方便,操作很不友好。
需求
加上快捷按钮,[上一年],[上一月],[下一年],[下一月],以及[重置]按钮。
效果图
上代码
1.日历组件 MyCalendar.vue
<template>
<div class="calendar">
<div class="showDate" @click="handleCalendarShow">
<span style="color:#000">范围:</span>
<span>{{ displayDate[0] }}</span>
<span> 至 </span>
<span>{{ displayDate[1] }}</span>
</div>
<van-calendar
ref="calendar"
v-model="show"
type="range"
color="#1989fa"
@confirm="onConfirm"
@month-show="dateChange"
:min-date="minDate"
:max-date="maxDate"
>
<template v-slot:title>
<div class="timeSelect">
<span @click="scrollToDate('down', 'year')" class="btn">上一年</span>
<span @click="scrollToDate('down', 'month')" class="btn">上一月</span>
<span @click="reset" class="btn">重置</span>
<span @click="scrollToDate('up', 'month')" class="btn">下一月</span>
<span @click="scrollToDate('up', 'year')" class="btn">下一年</span>
</div>
</template>
</van-calendar>
</div>
</template>
<script>
import Vue from 'vue'
import moment from 'moment'
import { Calendar, Toast } from 'vant'
import { defaultDate, dateRangeMinMax, dateFormat } from './config'
Vue.use(Calendar)
Vue.use(Toast)
export default {
name: 'demoPage',
data() {
return {
// 日历副标题
titleDate: {
date: defaultDate[1],
title: '选择日期'
},
// 日期格式
dateFormat,
minDate: dateRangeMinMax[0],
maxDate: dateRangeMinMax[1],
//默认时间范围
defaultDate,
//当前选择时间
date: defaultDate,
// 日期选择范围
dateRangeMinMax,
// 日历弹窗是否展示
show: false
}
},
computed: {
//用于展示的时间
displayDate() {
return [moment(this.date[0]).format(dateFormat), moment(this.date[1]).format(dateFormat)]
}
},
mounted() {},
methods: {
//日历弹窗方法
handleCalendarShow() {
this.show = true
setTimeout(() => {
//设置日历转到最新日期的展示界面
}, 300)
this.$refs.calendar.scrollToDate(new Date())
},
//选择日期触发方法
onConfirm(date) {
this.show = false
this.date = date
},
//重置时间选择为默认时间
reset() {
this.date = this.defaultDate
this.$refs.calendar.reset(this.defaultDate)
},
//日历视图滚动时更新日历副标题数据
dateChange(data) {
let transDate = moment(data.date).add(1, 'months')
if (transDate <= dateRangeMinMax[1] && transDate >= dateRangeMinMax[0]) {
if (moment(transDate).diff(moment(dateRangeMinMax[0]), 'months') < 1) {
transDate = moment(data.date)
}
const yearNum = transDate.format('YYYY')
const monthNum = parseInt(transDate.format('MM'))
const newDate = {
date: new Date(transDate.format()),
title: yearNum + '年' + monthNum + '月'
}
this.titleDate = newDate
}
},
//视图滚动到指定日期的视图
scrollToDate(type, dateType) {
let transDate = ''
if (type == 'up') {
transDate = moment(this.titleDate.date).add(1, dateType)
}
if (type == 'down') {
transDate = moment(this.titleDate.date).add(-1, dateType)
}
const leftDiffMonths = moment(transDate).diff(moment(dateRangeMinMax[1]), 'months')
const rightDiffMonths = moment(dateRangeMinMax[0]).diff(moment(transDate), 'months')
// 控制翻页范围,超出就提示
if (leftDiffMonths <= -193 || rightDiffMonths < -194) {
Toast.fail('已超出最大可选范围')
return null
}
const yearNum = transDate.format('YYYY')
const monthNum = parseInt(transDate.format('MM'))
const newDate = {
date: new Date(transDate.format()),
title: '选择日期'
}
this.titleDate = newDate
this.$refs.calendar.scrollToDate(new Date(newDate.date))
}
},
watch: {
date: {
handler() {
this.$emit('dateChange', this.displayDate)
},
immediate: true,
deep: true
}
}
}
</script>
<style lang="scss" scoped>
.calendar {
width: 100%;
display: flex;
justify-content: space-evenly;
align-items: center;
box-sizing: border-box;
padding: 0;
color: #989898;
position: relative;
.showDate {
width: 100%;
height: 28.6px;
display: flex;
align-items: center;
}
.timeSelect {
width: 100%;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 35px;
.btn {
display: inline-block;
margin-top: 10px;
padding: 0;
width: 54px;
height: 30px;
line-height: 30px;
border: 1px solid #dfdfdf;
border-radius: 4px;
font-size: 12px;
}
}
}
</style>
2.统一配置文件 config.js
import moment from 'moment'
export const minDate = new Date(2020, 1, 1)
export const maxDate = new Date(2030, 12, 31)
export const bottomInfoTxt = '数据加载中...'
export const defaultTypeName = '月度'
export const defaultTypeValue = 'month'
// 维度范围下拉框数据
export const optionType = [
{ text: '年', value: 'year' },
{ text: '季度', value: 'season' },
{ text: '月度', value: 'month' },
{ text: '天', value: 'day' }
]
// 时间格式
export const dateFormat = 'YYYY-MM-DD'
//默认开始时间和结束时间
const defaultStartDay = moment().add(-3, 'month')
const defaultEndDay = moment().add(1, 'day')
//可选的最大和最小时间范围
const minRangeDate = moment().add(-8, 'year')
const maxRangeDate = moment().add(2, 'year')
//时间筛选框的默认开始时间和结束时间
export const defaultDate = [new Date(defaultStartDay), new Date(defaultEndDay)]
//日期选择限制范围
export const dateRangeMinMax = [new Date(minRangeDate), new Date(maxRangeDate)]
3.父组件引入MyCalendar.vue
<div class="searchBox">
<van-cell class="width70">
<Calendar ref="calendar" @dateChange="dateChange" />
</van-cell>
<van-cell class="width30" @click="searchByParams">
<span class="btn">搜索</span>
</van-cell>
</div>
import {
bottomInfoTxt,
defaultDate,
minDate,
maxDate,
defaultTypeName,
defaultTypeValue,
optionType
} from './config'
import Calendar from './calendar.vue'
import {
List,
Toast,
DropdownMenu,
DropdownItem,
Picker,
Popup
} from 'vant'
export default {
name: 'ReportDetail',
components: { Calendar },
data() {
return {
bottomInfoTxt,
finished: true,
typeName: defaultTypeName,
typeValue: defaultTypeValue,
startDate: '',
endDate: '',
minDate,
maxDate,
optionType,
}
},
created() {
console.log('defaultDate:', defaultDate)
this.startDate = this.formatDate1(defaultDate[0])
this.endDate = this.formatDate1(defaultDate[1])
this.searchByParams()
},
methods: {
dateChange(dates) {
console.info('dates:', dates)
this.startDate = dates[0]
this.endDate = dates[1]
},
resetDate() {
this.$refs.calendar.reset()
},
formatDate1(value) {
const date = value || new Date()
const y = date.getFullYear()
let m = date.getMonth() + 1
m = m < 10 ? '0' + m : m
let d = date.getDate()
d = d < 10 ? '0' + d : d
return `${y}-${m}-${d}`
},
formatDate2(date) {
return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
},
async searchByParams() {},
onLoad() {}
}
}
效果
版权归原作者 asdf_anuo 所有, 如有侵权,请联系我们删除。