效果:

部分代码

.vue

<template><div class="date-select"><div class="date-select__custom"><span class="date-select__custom--text">自定义日期</span><span class="date-select__custom--value"><span v-if="dateData.length" v-html="dateText"></span><span v-else>请选择日期</span></span></div><div class="date-select__header" v-if="loading"><div class="date-select__header-prev"><span class="date-select__btn date-select__btn-prev--year">&lt;&lt;</span><span class="date-select__btn date-select__btn-prev--month">&lt;</span></div><div class="date-select__header-middle">{{ year }} 年 {{ month }} 月</div><div class="date-select__header-next"><span class="date-select__btn date-select__btn-next--month">&gt;</span><span class="date-select__btn date-select__btn-next--year">&gt;&gt;</span></div></div><div class="date-select__body"><div class="date-select__weeks"><div class="date-select__week" v-for="i in week" :key="i">{{ i }}</div></div><div class="date-select__month" v-if="loading"><div :class="['date-select__day', i.date < i.showDate && 'prev-month', i.date > i.showDate && 'next-month']" v-for="i in monthData" :key="i.date">{{ i.showDate }}</div></div></div></div>
</template>

js:

export default {name: 'date-select',props: {selectData: {type: Array,default: () => []},type: {type: String,default: 'date'},isOpen: {type: Boolean,default: false}},data() {return {monthData: [],week: ['日', '一', '二', '三', '四', '五', '六'],year: '',month: '',start: null,end: null,dateData: [],oldDateData: [],loading: true}},watch: {isOpen: {handler(val) {if (val) {this.dateData = this.selectDataconst [startDateArr, endDateArr] = [this.dateData?.[0]?.split('-'), this.dateData?.[1]?.split('-')]this.start = startDateArr == null ? null : new Date(startDateArr[0], startDateArr[1] - 1, startDateArr[2])this.end = endDateArr == null ? null : new Date(endDateArr[0], endDateArr[1] - 1, endDateArr[2])// 更多筛选是 if 销毁if (this.atomic) {this.oldDateData = this.selectData}// 默认筛选框是 show 销毁this.init()}},immediate: true}},computed: {dateText() {return `<span class="start-date">${this.dateData?.[0]}${this.dateData?.[1] == null ? '</span>' : '</span> 至 <span class="end-date">' + this.dateData?.[1]}`}},mounted() {this.addEvent()},methods: {addEvent() {const $datePickerDom = document.querySelector('.date-select')$datePickerDom.addEventListener('click',e => {e.stopPropagation()const $target = e.targetconst targetClassList = $target.classListif ((!targetClassList.contains('date-select__btn') &&!targetClassList.contains('date-select__day') &&!targetClassList.contains('start-date') &&!targetClassList.contains('end-date')) ||targetClassList.contains('date-select__btn--disabled') ||targetClassList.contains('date-select__day--disabled')) {return}if (targetClassList.contains('date-select__btn') || targetClassList.contains('start-date') || targetClassList.contains('end-date')) {let fixDate = nullif (targetClassList.contains('date-select__btn-prev--year')) {fixDate = this.fixMonthToYear(this.year - 1, this.month)} else if (targetClassList.contains('date-select__btn-prev--month')) {fixDate = this.fixMonthToYear(this.year, this.month - 1)} else if (targetClassList.contains('date-select__btn-next--month')) {fixDate = this.fixMonthToYear(this.year, this.month + 1)} else if (targetClassList.contains('date-select__btn-next--year')) {fixDate = this.fixMonthToYear(this.year + 1, this.month)} else {// 点击日期跳转到对应日期const dateArr = $target.innerHTML.split('-')fixDate = this.fixMonthToYear(+dateArr[0], +dateArr[1])}this.setMonthDate(fixDate.year, fixDate.month)} else if (targetClassList.contains('date-select__day')) {const dayType = this.judgeDayType(targetClassList)// 设置日期开始和结束时间,并返回设置的状态this.setStartEndDate(dayType, $target)this.dateData = [this.formatDate(this.start), this.formatDate(this.end)]}this.reRender()},false)},swipeRight() {const fixDate = this.fixMonthToYear(this.year, this.month - 1)this.setMonthDate(fixDate.year, fixDate.month)this.reRender()},swipeLeft() {const fixDate = this.fixMonthToYear(this.year, this.month + 1)this.setMonthDate(fixDate.year, fixDate.month)this.reRender()},// 重新渲染reRender() {// 通过开关 loading,来清空已点击选项this.clearUI()this.$nextTick().then(() => {this.renderUI()this.renderClickUI()})},init(year = this.start?.getFullYear(), month = this.start?.getMonth() + 1) {this.setMonthDate(year, month)this.reRender()},// 渲染未来时间不可选renderUI() {const fixDate = this.fixMonthToYear(this.year, this.month + 1)const date = new Date(fixDate.year, fixDate.month - 1)const today = new Date()// 下一年、下一月if (date - today > 0) {const monthDomClassList = document.getElementsByClassName('date-select__btn-next--month')[0].classListconst yearDomClassList = document.getElementsByClassName('date-select__btn-next--year')[0].classListmonthDomClassList.add('date-select__btn--disabled')yearDomClassList.add('date-select__btn--disabled')}// 下一天const dateDoms = document.getElementsByClassName('date-select__day')const dateDomsLength = dateDoms.lengthfor (let i = 0; i < dateDomsLength; i++) {const dateData = this.monthData[i]const date = new Date(dateData?.year, dateData?.month - 1, dateData?.showDate)if (date - today > 0) {while (i < dateDomsLength) {const domClassList = dateDoms[i].classListdomClassList.add('date-select__day--disabled')i++}}}},// 通过开始和结束时间,设置页面点击样式renderClickUI() {// 没点击,则无需渲染if (!this.start) {return}// 获取当前渲染日期界面的第一个和最后一个日期const [first, last] = [this.monthData[0], this.monthData[this.monthData.length - 1]]// 当点击的时间不在开始和结束的范围内,则无需渲染const firstDate = new Date(first.year, first.month - 1, first.showDate)const lastDate = new Date(last.year, last.month - 1, last.showDate)if (this.start - lastDate > 0 || (this.end && this.end - firstDate < 0)) {return}// 赋值新的点击、包括中间状态、开始和结束// 遍历每个日期const dateDoms = document.getElementsByClassName('date-select__day')for (let i = 0; i < dateDoms.length; i++) {const dateData = this.monthData[i]const date = new Date(dateData.year, dateData.month - 1, dateData.showDate)const domClassList = dateDoms[i].classList// 只有开始,给开始设置样式if (!this.end && this.start - date === 0) {domClassList.add('date-select__day--start')break}// 开始和结束都有// 设置开始if (this.start - date === 0) {// 当点击相同的if (this.end === this.start) {domClassList.remove('date-select__day--start')this.start = nullthis.end = nullthis.dateData = []break} else {// 给开始添加范围样式domClassList.add('date-select__day--start', 'select-both')}continue} else if (this.start - date < 0 && date - this.end < 0) {// 渲染中间的样式domClassList.add('date-select__day--middle')continue} else if (this.end - date === 0) {// 渲染结束的样式domClassList.add('date-select__day--end', 'select-both')break}}},// 判断当前点击的日期是上个月,这个月,还是当前月份的judgeDayType(classList) {let dayType = 'currMonth'if (classList.contains('prev-month')) {dayType = 'prevMonth'} else if (classList.contains('next-month')) {dayType = 'nextMonth'}return dayType},// 设置开始和结束日期setStartEndDate(dayType, dom) {const day = dom.innerHTMLlet clickDate = nulllet fixDate = nullswitch (dayType) {case 'currMonth':fixDate = this.fixMonthToYear(this.year, this.month)breakcase 'prevMonth':fixDate = this.fixMonthToYear(this.year, this.month - 1)breakcase 'nextMonth':fixDate = this.fixMonthToYear(this.year, this.month + 1)break}clickDate = new Date(fixDate.year, fixDate.month - 1, day)// 清空已选的开始和结束,只点击了开始if (!this.start || (this.start && this.end)) {this.start = clickDatethis.end = null} else if (this.start - clickDate === 0) {// 开始和结束都在同一天this.end = this.start} else if (this.start - clickDate > 0) {// 交换结束和开始this.end = this.startthis.start = clickDate} else {// 设置结束this.end = clickDate}},setMonthDate(year, month) {// 若没有传入年月,则默认选择当前年月if (!year || !month) {const today = new Date()year = today.getFullYear()month = today.getMonth() + 1 // 例如想要的是12月,getMonth() 会返回 11(js 里的 month 总是会比实际的少 1)}// 当月第一天相关let firstDateOfCurrMonth = new Date(year, month - 1, 1) // 获取当月第一天let weekOfFirstDate = firstDateOfCurrMonth.getDay() // 当月第一天是一周的星期几。那么之前的时间是上个月的// 周日if (weekOfFirstDate === 0) {weekOfFirstDate = 7}// 上个月最后一天相关let lastDateOfLastMonth = new Date(year, month - 1, 0) // 上个月最后一天 年月日let lastDayOfLastMonth = lastDateOfLastMonth.getDate() // 上个月最后一天 日let preMonthDayCount = weekOfFirstDate // 本月第一行,留有上个月的天数。因为是从周日开始的。若 1 号为周二,那么留有上个月的天数为 2(周日、周一)let lastDateOfCurrMonth = new Date(year, month, 0) // 本月的最后一天 年月日let lastDayOfCurrMonth = lastDateOfCurrMonth.getDate() // 本月的最后一天 日// 设置月的范围let range = 5 * 7let allDayCount = lastDayOfCurrMonth + preMonthDayCountif (allDayCount > range) {// 会有 6 行range += 7} else if (allDayCount <= range - 7) {// 只有 4 行range -= 7}this.monthData = this.getMonthData(range, year, month, preMonthDayCount, lastDayOfLastMonth, lastDayOfCurrMonth)this.year = yearthis.month = month},getMonthData(range, year, month, preMonthDayCount, lastDayOfLastMonth, lastDayOfCurrMonth) {const ret = []let date, showDate, currMonthfor (let i = 0; i < range; i++) {date = i + 1 - preMonthDayCount // 本月的几号showDate = datecurrMonth = month// 上个月if (date <= 0) {currMonth = month - 1showDate = lastDayOfLastMonth + date // 上个月的第几号} else if (date > lastDayOfCurrMonth) {// 下一个月currMonth = month + 1showDate = showDate - lastDayOfCurrMonth // 下个月的第几号}const fixDate = this.fixMonthToYear(year, currMonth)ret.push({year: fixDate.year,month: fixDate.month,date,showDate})}return ret},fixMonthToYear(year, month) {// 若本月为 1 月,则上一月为 12 月if (month === 0) {month = 12year -= 1}// 若本月为 12 月,则下一月为 1 月if (month === 13) {month = 1year += 1}year = year || 0return { year, month }},formatDate(date) {if (!date) {return date}return `${date.getFullYear()}-${date.getMonth() + 1 < 10 ? `0${date.getMonth() + 1}` : date.getMonth() + 1}-${date.getDate() < 10 ? `0${date.getDate()}` : date.getDate()}`},// 重新渲染日历clearUI() {this.loading = falsethis.$nextTick(() => {this.loading = true})},cancel() {if (this.atomic) {this.confirmData('', this.oldDateData)} else {// 日期重置回当月this.dateData = []this.start = nullthis.end = nullthis.setMonthDate()this.reRender()}},confirm(type) {this.confirmData(type, this.dateData)},confirmData(type, dateData) {const value = dateData[1] ? [dateData[0], dateData[1]] : dateData[0] ? [dateData[0]] : []this.$emit('confirm', type, value)}}
}

用 Vue 实现原生日期选择器相关推荐

  1. 【vue开发问题-解决方法】(五)vue Element UI 日期选择器获取日期格式问题 t.getTime is not a function

    [vue开发问题-解决方法](五)vue Element UI 日期选择器获取日期格式问题 t.getTime is not a function 参考文章: (1)[vue开发问题-解决方法](五) ...

  2. 最好用的 12 款 Vue Timepicker 时间日期选择器测评推荐 - 卡拉云

    本文首发:<最好用的 12 款 Vue Timepicker 时间日期选择器测评推荐 - 卡拉云> Vue 时间日期选择器(date-timepicker)组件在使用 Vue 框架开发中使 ...

  3. vue element的日期选择器 ,选择日期时间范围的限制

    最近在做活动配置,那么就会需要配置活动的开始时间和活动的结束时间,对于活动开始时间选择范围是不能今天之前时间的,活动的结束时间也是,是不能选择今天之前的时间和活动开始之前时间的,有了明确的目的,现在就 ...

  4. vue使用element日期选择器,选择日期少一天的问题

    添加属性value-format="yyyy-MM-dd"即可

  5. vue日期选择组件_一个Vue组件,为波斯开发人员提供日期选择器

    vue日期选择组件 Vue波斯日期选择器 (vue persian datepicker) This is a Jalali date picker component for Vue. 这是Vue的 ...

  6. vue【element ui】el-date-picker 日期选择器控件 限制可选的开始时间和结束时间

    项目场景: 总结一下日期控件实现开始日期.结束日期的选择范围限制,以便更符合实际情况. 需求: 1.开始时间和结束时间都不能选当前日期之后的时间.(当前时间:2022年5月16日) 2.先选开始时间的 ...

  7. android 日期对话框,Android日期选择器对话框DatePickerDialog使用详解

    调用Android原生日期选择器对话框就是DatePickerDialog,具体内容如下 在Android4.4系统上效果如图: 在Android5.0以上效果如图: 1.Activity的onCre ...

  8. js日期控件_11个开源的Github开源日期选择器组件,供你选择

    介绍 本文主要介绍几个Vue的时间日期选择器组件,目的在于让开发者们多一些选择,不管是从功能还是从样式,都可以选择一个适合的组件,这些组件没有绝对的好与不好,就看个人如何选择了,以下分别介绍十一个日期 ...

  9. android时间选择原生,安卓原生时间选择器

    调用Android原生日期选择器对话框也就是DatePickerDialog package com.example.myapplication; import android.app.DatePic ...

最新文章

  1. 32位oracle_Oracle 之Hugepage
  2. Evaluation of hybrid and non-hybrid methods for de novo assembly of nanopore reads
  3. 关闭eslint检查2020_2020 vscode配置eslint保存后自动fix
  4. LeetCode:925. Long Pressed Name
  5. composer的基本运用
  6. TreeView控件之,后台构建TreeView(WinForm小程序)
  7. ITK:在不复制内存的情况下为每个像素添加常量
  8. 链表定义、链表的插入、链表的删除、链表的查找
  9. P4819-[中山市选]杀人游戏【tarjan】
  10. 100转换成二进制 java,一段简单的java代码,十进制转二进制
  11. 用火车头采集小游戏网站教程[转载]
  12. 用python计算绩点的代码_【Python】计算GPA
  13. BookKeeper总结
  14. QT接收Linux内核,QT界面程序经过网路与普通的linux应用程序进行数据传送的情况...
  15. CSDN获得积分的方法
  16. 编程不是一种知识,而是一门手艺。
  17. 金融行业数据容灾架构中的数据复制技术
  18. WordPress 安全漏洞
  19. 小红书api_【实习精选】oppo、小红书等名企实习汇总(96)
  20. 提高win7系统运行速度的方法

热门文章

  1. hanlp源码解读之字符正规化CharTable
  2. 分布式缓存Redis之发布/订阅(Pub/Sub)
  3. 网球小组赛对阵表如何php,网球比赛规则 看完就明白
  4. nginx 关闭某个请求的日志记录
  5. Web后端框架Springboot创建和基础讲解(一)
  6. 微软大牛邹欣老师带你写出你的第一个 AI 应用
  7. php除以100保留两位小数点,php保留两位小数的几种方法介绍
  8. Flask+MySQL大数据表格分页显示
  9. OAuth,JWT ,OIDC你们搞得我好乱啊
  10. 基于spdlog实现日志控制台输出、文件输出或控制台+文件同时输出