0


【vue2 + vant UI】基于Vant的日历组件封装可翻页选年和月的日历组件

场景

使用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() {}
  }
}

效果

在这里插入图片描述
在这里插入图片描述


本文转载自: https://blog.csdn.net/weixin_44482361/article/details/139630584
版权归原作者 asdf_anuo 所有, 如有侵权,请联系我们删除。

“【vue2 + vant UI】基于Vant的日历组件封装可翻页选年和月的日历组件”的评论:

还没有评论