300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 自定义 “至今”选项日期选择器

自定义 “至今”选项日期选择器

时间:2023-05-25 10:38:22

相关推荐

自定义 “至今”选项日期选择器

实现缘由

有这么一个分享的原因是,我发现很多选择日期的地方都会要求能选择“至今”,但是现在广泛使用的UI库中,都是不支持的。很奇怪,这个需求还是挺常见的,为什么都不支持呢?网上类似的控件也很难找,几乎没找到。所以我自定义了这么一款控件,基于vant picker 来实现的,但是,如果想依赖于其他的UI库,也是比较好迁移过去实现的。

效果图

代码分享

<template><div class="container"><van-popup v-model="isShow" position="bottom" @close="onClosePop"><van-pickerref="van_picker":columns="columns"show-toolbar:title="pickerShowTitle"@confirm="onConfirm"@cancel="onCancle"@change="onChange"/></van-popup></div></template><script lang="ts">import {Component, Prop, Vue, Watch} from 'vue-property-decorator'@Component({name: 'CustomDate'})export default class CustomDate extends Vue {public $refs!: {van_picker: HTMLFormElement;};@Prop({type: Boolean,default: false})isShowProp!: boolean;@Prop({type: Boolean,default: false})isMultiProp!: boolean;@Prop({type: String,default: ''})showTimeProp!: string;@Prop({type: String,default: ''})titleProp!: string;columns: any = [];isShow: boolean = this.isShowProp;isMulti: boolean = this.isMultiProp;showTime = this.showTimeProp;pickerTitle = this.titleProp.split('-');pickerShowTitle = '';multiShowTime = '';@Watch('isShowProp', {deep: true})watchisShow(data: any) {this.isShow = data;this.$nextTick(()=>{this.pickerShowTitle = this.pickerTitle[0];this.showTime = this.showTimeProp;this.timeInit();})}initLastData() {const myDate = new Date();const data = {year: myDate.getFullYear(),month: myDate.getMonth() + 1,date: myDate.getDate(),};const options1 = [{ text: "至今", value: -1 }],options2 = [], options3 = [], dataFull = [];//初始化近30年for (let i = data.year; i > data.year - 31; i--) {options1.push({text: i + "",value: i,});}if (this.showTime !== '至今' && this.showTime !== '') {const arr = this.showTime.split('-')for (let j = 1; j <= data.month ; j++) {options2.push({text: j < 10 ? "0" + j : "" + j,value: j,});}// 非当前年for (let z = 1; z <= 12; z++) {dataFull.push({text: z < 10 ? '0' + z : '' + z,value: z < 10 ? '0' + z : '' + z})}// 初始化当前月天数数据,限制小于等于今天for (let j = 1; j <= data.date; j++) {options3.push({text: j < 10 ? "0" + j : "" + j,value: j,});}this.columns = [{ values: options1 },{ values: parseInt(arr[0]) < data.year ? dataFull : options2 },{ values: options3 },];} else {this.columns = [{values: options1}, {values: []},{values: []}];}}onConfirm(value: any) {let date: any = '';value.forEach((item: any, index: any) => {if(item) {date += index === 0 ? ''+ item.text : '-' + item.text;}});if (this.isMulti) {if (this.pickerShowTitle !== this.pickerTitle[1]) {// 第一次选择时间this.showTime = date;this.pickerShowTitle = this.pickerTitle[1];// 限制时间this.timeLimit(this.showTime)} else {// 第二次选择this.multiShowTime = this.showTime + '-' + date;this.$emit('onConfirm',this.multiShowTime);}} else {this.showTime = date;this.$emit('onConfirm',date)}}onCancle() {this.$emit('onCancle')}onClosePop() {this.$emit('onCancle')}// 限制选择起始时间后时间timeLimit(startTime: string) {const myDate = new Date()const data = {year: myDate.getFullYear()}const arr = startTime.split('-')const options1 = [{ text: "至今", value: -1 }], options2 = [], options3 = []for (let i = data.year; i >= parseInt(arr[0]); i--) {options1.push({text: i + "",value: i,});}for (let j = 12; j >= parseInt(arr[1]); j--) {options2.push({text: j < 10 ? '0' + j : '' + j,value: j})}const isLeapYear = parseInt(arr[0]) % 4 === 0 && parseInt(arr[0]) % 100 !== 0 || parseInt(arr[0]) % 400 === 0;const nowMonth = isNaN(parseInt(arr[0])) ? -1 : parseInt(arr[1]);const isBigMonth = [1,3,5,7,8,10,12].indexOf(nowMonth) !== -1;for (let k = (isBigMonth? 31: (nowMonth === 2? (isLeapYear? 29:28) : 30)); k >= parseInt(arr[2]); k--) {options3.push({text: k < 10 ? '0' + k : '' + k,value: k})}this.$refs.van_picker.setColumnValues(0, options1)this.$refs.van_picker.setColumnValues(1, options2.reverse())this.$refs.van_picker.setColumnValues(2, options3.reverse())this.$refs.van_picker.setColumnValue(0, arr[0])this.$refs.van_picker.setColumnValue(1, arr[1])this.$refs.van_picker.setColumnValue(2, arr[2])}onChange(picker: any, values: any, index: any) {const myDate = new Date()const year = myDate.getFullYear()const month = myDate.getMonth() + 1const dataFull = [],options2 = [],options3 = []// 滑动年份数据if (index === 0) {const arr = this.showTime.split('-')if (this.isMulti && this.pickerShowTitle === this.pickerTitle[1] && parseInt(arr[0]) === values[0].value) {this.timeLimit(this.showTime)return;}for (let z = 1; z <= 12; z++) {dataFull.push({text: z < 10 ? '0' + z : z,value: z})}for (let j = 1; j <= month; j++) {options2.push({text: j < 10 ? '0' + j : j,value: j})}//如果选项变成至今,则月份选项为空if (values[0].value === -1) {picker.setColumnValues(1, [])picker.setColumnValues(2, [])return}//如果年选项小于当前年,则显示12个月if (values[0].value < year) {picker.setColumnValues(1, dataFull)} else {picker.setColumnValues(1, options2)}if (options3.length === 0) {const isLeapYear = values[0].value % 4 === 0 && values[0].value % 100 !== 0 || values[0].value % 400 === 0;const nowMonth = (values[0].value < year) ? dataFull[0].value : options2[0].value;const isBigMonth = [1,3,5,7,8,10,12].indexOf(nowMonth) !== -1;for (let j = 1; j <= (isBigMonth? 31: (nowMonth === 2? (isLeapYear? 29:28) : 30)); j++) {options3.push({text: j < 10 ? '0' + j : j,value: j})}picker.setColumnValues(2, options3)}} else if (index === 1) { // 滑动月份数据const arr = this.showTime.split('-')if (this.isMulti && this.pickerShowTitle === this.pickerTitle[1] && parseInt(arr[1]) === values[1].value) {this.timeLimit(this.showTime)return;}const isLeapYear = values[0].value % 4 === 0 && values[0].value % 100 !== 0 || values[0].value % 400 === 0;const isBigMonth = [1,3,5,7,8,10,12].indexOf(values[1].value) !== -1;for (let j = 1; j <= (isBigMonth? 31: (values[1].value === 2? (isLeapYear? 29:28) : 30)); j++) {options3.push({text: j < 10 ? '0' + j : j,value: j})}picker.setColumnValues(2, options3)}}timeInit(){const myDate = new Date()const data = {year: myDate.getFullYear(),month: myDate.getMonth() + 1}const arr = this.showTime.split('-')const options1 = [{ text: "至今", value: -1 }], dataFull = [], options2 = [], options3 = []if (this.showTime != '至今' && this.showTime !== '') {for (let i = data.year; i > data.year - 31; i--) {options1.push({text: i + "",value: i,});}// 12个月for (let z = 1; z <= 12; z++) {dataFull.push({text: z < 10 ? '0' + z : '' + z,value: z})}//小于当前月的选项for (let j = 1; j <= data.month; j++) {options2.push({text: j < 10 ? '0' + j : '' + j,value: j})}const isLeapYear = parseInt(arr[0]) % 4 === 0 && parseInt(arr[0]) % 100 !== 0 || parseInt(arr[0]) % 400 === 0;const nowMonth = isNaN(parseInt(arr[0])) ? -1 : parseInt(arr[1]);const isBigMonth = [1,3,5,7,8,10,12].indexOf(nowMonth) !== -1;if (nowMonth !== -1) {for (let j = 1; j <= (isBigMonth? 31: (nowMonth === 2? (isLeapYear? 29:28) : 30)); j++) {options3.push({text: j < 10 ? '0' + j : j + '',value: j})}}this.$refs.van_picker.setColumnValues(0, options1)//回填月份数据if (parseInt(arr[0]) < data.year) {this.$refs.van_picker.setColumnValues(1, dataFull)} else {this.$refs.van_picker.setColumnValues(1, options2)}// 回填天数数据this.$refs.van_picker.setColumnValues(2, options3)//回填选中的值this.$refs.van_picker.setColumnValue(0, arr[0])this.$refs.van_picker.setColumnValue(1, arr[1])this.$refs.van_picker.setColumnValue(2, arr[2])} else {this.$refs.van_picker.setColumnIndex(0, 0, 0)this.$refs.van_picker.setColumnValues(1, [])this.$refs.van_picker.setColumnValues(2, [])}}mounted() {this.initLastData();}}</script><style lang="scss">.container {}</style>

如何使用

import CustomDate from "@/components/CustomDate.vue";<CustomDate@onCancle="onCusDateCancle"@onConfirm="onCusDateConfirm":isShowProp="isShowPop":showTimeProp="showTimeProp"titleProp="起始时间-结束时间"isMultiProp></CustomDate>

titleProp: 设置标题,以"-"分隔 实现区间选择的两个标题显示

isMutiprop: 设置是否开启区间选择

实现的原理

主要是基于 vant picker 的setColumnValues

来实现动态的日期显示,所以,原理其实挺简单,这里也是做一个分享,有需要的小伙伴可以拿来直接用,找不到合适的控件真的很难受。

这里感谢/weixin_40408338/article/details/105159765 提供了实现的思路,大家也可以看一下这位作者的文章,实现了年月的联动,比较清晰。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。