123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679 |
- <template>
- <view class="datatime">
- <picker mode="multiSelector" :range="range" range-key="text" @change="change" @columnchange="columnchange" :value="value" :disabled="disabled">
- <view class="dis-fix">
- <view class="content" :class="{ placeholder: !dateStr }">
- <text>{{ dateStr ? dateStr : placeholder }}</text>
- </view>
- <slot></slot>
- </view>
- </picker>
- </view>
- </template>
- <script>
- export default {
- /**
- * 数据
- */
- props: {
- // 是否禁用
- disabled: {
- type: Boolean,
- default: false
- },
- // 占位符
- placeholder: {
- type: String,
- default: '请选择日期时间'
- },
- // 表示有效日期时间范围的开始,
- // 字符串格式为 "YYYY-MM-DD hh:mm"
- start: {
- type: String,
- default: '1970-1-1 00:00'
- },
- // 表示有效日期时间范围的结束
- // 字符串格式为 "YYYY-MM-DD hh:mm"
- end: {
- type: String,
- default: '2300-1-1 00:00'
- },
- // 表示选择器的粒度,有效值:year | month | day | hour | minute
- fields: {
- type: String,
- default: 'minute'
- },
- // 默认值
- // 字符串格式为 "YYYY-MM-DD hh:mm"
- defaultValue: {
- type: String,
- default: ''
- }
- },
- /**
- * 数据
- */
- data() {
- return {
- range: [],
- value: [],
- dateStr: '', // 最终显示的字符串
- dtStart: null, // 有效范围开始
- dtEnd: null, // 有效范围结束
- };
- },
-
- /**
- * 监听数据
- */
- watch: {
- // 默认值
- defaultValue() {
- // 设置默认值
- this.setDefaultValue();
- }
- },
- /**
- * 组件初次加载完成
- */
- mounted() {
- // 有效日期开始和结束
- let start = this.start;
- let end = this.end;
-
- // 验证是否是有效的开始和结束日期
- if(!this.isString(this.start)) {
- console.log('开始日期需为String类型,格式为 "YYYY-MM-DD hh:mm"');
- start = '1970-1-1 00:00';
- }
- if(!this.isString(this.start)) {
- console.log('结束日期需为String类型,格式为 "YYYY-MM-DD hh:mm"');
- start = '2300-1-1 00:00';
- }
-
- // 将开始日期和结束日期转为 Date
- let dtStart = this.formatDate(start).dt;
- let dtEnd = this.formatDate(end).dt;
-
- // 判断有效日期结束是否大于有效日期开始,如果不是,则将有效日期结束修改为有效日期开始往后300年
- if (dtEnd <= dtStart) {
- dtEnd = this.formatDate(start).dt;
- dtEnd.setFullYear(dtStart.getFullYear() + 300);
- dtEnd.setDate(dtEnd.getDate() - 1);
- }
-
- // 更新开始日期和结束日期
- this.dtStart = dtStart;
- this.dtEnd = dtEnd;
- // 设置默认值
- this.setDefaultValue();
- },
- /**
- * 方法
- */
- methods: {
- /**
- * 确认选择
- */
- change(event) {
- let year, month, day, hour, minute;
- if(this.fields == 'year') {
- year = this.range[0][this.value[0]].number; // 年
- let dtStr = `${year}`;
- this.setDateStr(dtStr);
- this.$emit('change', this.formatDate(dtStr));
- return;
- }
- else if(this.fields == 'month') {
- year = this.range[0][this.value[0]].number; // 年
- month = this.range[1][this.value[1]].number; // 月
- let dtStr = `${year}-${month}`;
- this.setDateStr(dtStr);
- this.$emit('change', this.formatDate(dtStr));
- return;
- }
- else if(this.fields == 'day') {
- year = this.range[0][this.value[0]].number; // 年
- month = this.range[1][this.value[1]].number; // 月
- day = this.range[2][this.value[2]].number; // 日
- let dtStr = `${year}-${month}-${day}`;
- this.setDateStr(dtStr);
- this.$emit('change', this.formatDate(dtStr));
- return;
- }
- else if(this.fields == 'hour') {
- year = this.range[0][this.value[0]].number; // 年
- month = this.range[1][this.value[1]].number; // 月
- day = this.range[2][this.value[2]].number; // 日
- hour = this.range[3][this.value[3]].number; // 时
- day = this.range[2][this.value[2]].number; // 日
- let dtStr = `${year}-${month}-${day} ${hour}`;
- this.setDateStr(dtStr);
- this.$emit('change', this.formatDate(dtStr));
- return;
- }
- else if(this.fields == 'minute') {
- year = this.range[0][this.value[0]].number; // 年
- month = this.range[1][this.value[1]].number; // 月
- day = this.range[2][this.value[2]].number; // 日
- hour = this.range[3][this.value[3]].number; // 时
- minute = this.range[4][this.value[4]].number; // 分
- let dtStr = `${year}-${month}-${day} ${hour}:${minute}`;
- this.setDateStr(dtStr);
- this.$emit('change', this.formatDate(dtStr));
- return;
- }
- },
- /**
- * 设置显示的值
- * @param {Date|String} date 日期字符串或日期对象
- */
- setDateStr(date) {
- let dt = this.formatDate(date);
- if(this.fields == 'year') {
- this.dateStr = `${dt.YYYY}年`;
- return;
- }
- if(this.fields == 'month') {
- this.dateStr = `${dt.YYYY}年${dt.M}月`;
- return;
- }
- if(this.fields == 'day') {
- this.dateStr = `${dt.YYYY}年${dt.M}月${dt.D}日`;
- return;
- }
- if(this.fields == 'hour') {
- this.dateStr = `${dt.YYYY}年${dt.M}月${dt.D}日 ${dt.h}时`;
- return;
- }
- this.dateStr = `${dt.YYYY}-${dt.M}-${dt.D} ${dt.h}:${dt.m}`;
- },
-
- /**
- * 设置年数据
- */
- setYearData() {
- // 有效日期
- let yearStart = this.dtStart.getFullYear();
- let yearEnd = this.dtEnd.getFullYear();
- // 年
- let years = [];
- for (let year = yearStart; year <= yearEnd; year++) {
- let item = {
- number: year,
- text: `${year}年`,
- };
- years.push(item);
- }
- this.range.splice(0, 1, years);
- },
-
- /**
- * 设置月数据
- * @param {Number} year 年
- */
- setMonthData(year) {
- // 有效日期
- let yearStart = this.dtStart.getFullYear();
- let monthStart = this.dtStart.getMonth() + 1;
- let yearEnd = this.dtEnd.getFullYear();
- let monthEnd = this.dtEnd.getMonth() + 1;
-
- // 月
- let months = [];
- let monthStartIndex = year == yearStart ? monthStart : 1;
- let monthEndIndex = year == yearEnd ? monthEnd : 12;
- for (let month = monthStartIndex; month <= monthEndIndex; month++) {
- let item = {
- number: month,
- text: `${month}月`,
- };
- months.push(item);
- }
- this.range.splice(1, 1, months);
- },
-
- /**
- * 设置日数据
- * @param {Number} year 年
- * @param {Number} month 月
- */
- setDayData(year, month) {
- // 有效日期
- let yearStart = this.dtStart.getFullYear();
- let monthStart = this.dtStart.getMonth() + 1;
- let dayStart = this.dtStart.getDate();
- let yearEnd = this.dtEnd.getFullYear();
- let monthEnd = this.dtEnd.getMonth() + 1;
- let dayEnd = this.dtEnd.getDate();
-
- // 日
- let days = [];
- let dayStartIndex = year == yearStart && month == monthStart ? dayStart : 1;
- let dayEndIndex;
- if(year == yearEnd && month == monthEnd) {
- dayEndIndex = dayEnd;
- } else {
- // 本月1号
- let dtThisMonth = new Date();
- dtThisMonth.setFullYear(year);
- dtThisMonth.setMonth(month - 1);
- dtThisMonth.setDate(1);
- dtThisMonth.setHours(0);
- dtThisMonth.setMinutes(0);
- dtThisMonth.setSeconds(0);
- dtThisMonth.setMilliseconds(0);
-
- // 下月1号
- let dtNextMonth = new Date();
- dtNextMonth.setFullYear(year);
- dtNextMonth.setMonth(month);
- dtNextMonth.setDate(1);
- dtNextMonth.setHours(0);
- dtNextMonth.setMinutes(0);
- dtNextMonth.setSeconds(0);
- dtNextMonth.setMilliseconds(0);
-
- // 计算出本月的总天数
- dayEndIndex = parseInt((dtNextMonth - dtThisMonth) / (86400000));
- }
- for (let day = dayStartIndex; day <= dayEndIndex; day++) {
- let item = {
- number: day,
- text: `${day}日`,
- };
- days.push(item);
- }
- this.range.splice(2, 1, days);
- },
-
- /**
- * 设置时数据
- * @param {Number} year 年
- * @param {Number} month 月
- * @param {Number} day 日
- */
- setHourData(year, month, day) {
- // 有效日期
- let yearStart = this.dtStart.getFullYear();
- let monthStart = this.dtStart.getMonth() + 1;
- let dayStart = this.dtStart.getDate();
- let hourStart = this.dtStart.getHours();
- let yearEnd = this.dtEnd.getFullYear();
- let monthEnd = this.dtEnd.getMonth() + 1;
- let dayEnd = this.dtEnd.getDate();
- let hourEnd = this.dtEnd.getHours();
-
- // 时
- let hours = [];
- let hourStartIndex = year == yearStart && month == monthStart && day == dayStart ? hourStart : 0;
- let hourEndIndex = year == yearEnd && month == monthEnd && day == dayEnd ? hourEnd : 23;
- for (let hour = hourStartIndex; hour <= hourEndIndex; hour++) {
- let item = {
- number: hour,
- text: `${hour}时`,
- };
- hours.push(item);
- }
- this.range.splice(3, 1, hours);
- },
-
- /**
- * 设置分数据
- * @param {Number} year 年
- * @param {Number} month 月
- * @param {Number} day 日
- * @param {Number} hour 时
- */
- setMinuteData(year, month, day, hour) {
- // 有效日期
- let yearStart = this.dtStart.getFullYear();
- let monthStart = this.dtStart.getMonth() + 1;
- let dayStart = this.dtStart.getDate();
- let hourStart = this.dtStart.getHours();
- let minuteStart = this.dtStart.getMinutes();
- let yearEnd = this.dtEnd.getFullYear();
- let monthEnd = this.dtEnd.getMonth() + 1;
- let dayEnd = this.dtEnd.getDate();
- let hourEnd = this.dtEnd.getHours();
- let minuteEnd = this.dtEnd.getMinutes();
-
- // 分
- let minutes = [];
- let minuteStartIndex = year == yearStart && month == monthStart && day == dayStart && hour == hourStart ? minuteStart : 0;
- let minuteEndIndex = year == yearEnd && month == monthEnd && day == dayEnd && hour == hourEnd ? minuteEnd : 59;
- for(let minute = minuteStartIndex; minute <= minuteEndIndex; minute++) {
- let item = {
- number: minute,
- text: `${minute}分`,
- }
- minutes.push(item);
- }
- this.range.splice(4, 1, minutes);
- },
-
- /**
- * 设置默认值
- */
- setDefaultValue() {
- // 默认日期
- let dtDefault;
-
- // 开始日期和结束日期
- let dtStart = this.dtStart;
- let dtEnd = this.dtEnd;
-
- // 判断是否传了默认日期
- // 传了默认日期,格式化默认日期为日期对象
- if(this.defaultValue) {
- dtDefault = this.formatDate(this.defaultValue).dt;
- }
- // 如果没有传默认日期,将默认日期设置为当前日期
- else {
- dtDefault = new Date();
- }
-
- // 如果默认日期不在有效日期范围内,设置默认日期为有效日期开始值
- if (dtDefault < dtStart || dtDefault > dtEnd) {
- dtDefault = dtStart;
- }
-
- // 更新 dateStr
- if(this.defaultValue) this.setDateStr(dtDefault);
-
- // 默认值相关数据
- let dfYear = dtDefault.getFullYear();
- let dfMonth = dtDefault.getMonth() + 1;
- let dfDay = dtDefault.getDate();
- let dfHour = dtDefault.getHours();
- let dfMinute = dtDefault.getMinutes();
-
- // 设置年数据
- this.setYearData();
- // 设置 Year 这一列的 value 值
- let yearIndex = this.range[0].findIndex(year => {
- return dfYear == year.number;
- });
- this.value.splice(0, 1, yearIndex >= 0 ? yearIndex : 0);
-
- // 设置月数据
- if(this.fields == 'year') return;
- this.setMonthData(dfYear);
- // 设置 Month 这一列的 value 值
- let monthIndex = this.range[1].findIndex(month => {
- return dfMonth == month.number;
- });
- this.value.splice(1, 1, monthIndex >=0 ? monthIndex : 0);
-
- // 设置日数据
- if(this.fields == 'month') return;
- this.setDayData(dfYear, dfMonth);
- // 设置 Day 这一列的 value 值
- let dayIndex = this.range[2].findIndex(day => {
- return dfDay == day.number;
- });
- this.value.splice(2, 1, dayIndex >=0 ? dayIndex : 0);
-
- // 设置时数据
- if(this.fields == 'day') return;
- this.setHourData(dfYear, dfMonth, dfDay);
- // 设置 Hour 这一列的 value 值
- let hourIndex = this.range[3].findIndex(hour => {
- return dfHour == hour.number;
- });
- this.value.splice(3, 1, hourIndex >=0 ? hourIndex : 0);
-
- // 设置分数据
- if(this.fields == 'hour') return;
- this.setMinuteData(dfYear, dfMonth, dfDay, dfHour);
- // 设置 Minute 这一列的 value 值
- let minuteIndex = this.range[4].findIndex(minute => {
- return dfMinute == minute.number;
- });
- this.value.splice(4, 1, minuteIndex >=0 ? minuteIndex : 0);
- },
- /**
- * 某一列的值改变时触发
- * @param {Number} event.detail.column 表示改变了第几列(下标从0开始)
- * @param {Number} event.detail.value 表示变更值的下标
- */
- columnchange(event) {
- let columnIndex = event.detail.column; // 改变的列的下标
- let valueIndex = event.detail.value; // 变更值的下标
-
- // 更新改变列的 value
- this.value.splice(columnIndex, 1, valueIndex);
-
- // 改变年要更新月数据
- if(this.fields == 'year') return;
- if (columnIndex == 0) {
- // 当前选择的月
- let monthBeforeUpdate = this.range[1][this.value[1]];
- // 更新月数据
- this.setMonthData(this.range[0][this.value[0]].number);
- // 更新 Month Value
- let monthIndex = this.range[1].findIndex(month => {
- return month.number == monthBeforeUpdate.number;
- });
- this.value.splice(1, 1, monthIndex >= 0 ? monthIndex : 0);
- }
-
- // 改变年、月都要更新日数据
- if(this.fields == 'month') return;
- if (columnIndex == 0 || columnIndex == 1) {
- // 当前选择的日
- let dayBeforeUpdate = this.range[2][this.value[2]];
- // 更新日数据
- this.setDayData(this.range[0][this.value[0]].number, this.range[1][this.value[1]].number);
- // 更新 Day Value
- let dayIndex = this.range[2].findIndex(day => {
- return day.number == dayBeforeUpdate.number;
- });
- this.value.splice(2, 1, dayIndex >= 0 ? dayIndex : 0);
- }
-
- // 改变年、月、日都要更新时数据
- if(this.fields == 'day') return;
- if (columnIndex == 0 || columnIndex == 1 || columnIndex == 2) {
- // 当前选择的时
- let hourBeforeUpdate = this.range[3][this.value[3]];
- // 更新时数据
- this.setHourData(this.range[0][this.value[0]].number, this.range[1][this.value[1]].number, this.range[2][this.value[2]].number);
- // 更新 Hour Value
- let hourIndex = this.range[3].findIndex(hour => {
- return hour.number == hourBeforeUpdate.number;
- });
- this.value.splice(3, 1, hourIndex >= 0 ? hourIndex : 0);
- }
-
- // 当前选择的分
- if(this.fields == 'hour') return;
- let minuteBeforeUpdate = this.range[4][this.value[4]];
- // 更新分数据
- this.setMinuteData(this.range[0][this.value[0]].number, this.range[1][this.value[1]].number, this.range[2][this.value[2]].number, this.range[3][this.value[3]].number);
- // 更新 Minute Value
- let minuteIndex = this.range[4].findIndex(minute => {
- return minute.number == minuteBeforeUpdate.number;
- });
- this.value.splice(4, 1, minuteIndex >= 0 ? minuteIndex : 0);
- },
-
- /**
- * 判断数据是否是 String 类型
- * @param {Any} val 要判断的数据
- * @returns {Boolean} true:是;false:不是;
- */
- isString(val) {
- return Object.prototype.toString.call(val) === '[object String]';
- },
-
- /**
- * 精确判断数据是否是 Date 类型
- * @param {Any} val 要判断的数据
- * @returns {Boolean} true:是;false:不是;
- */
- isDate(val) {
- return Object.prototype.toString.call(val) === '[object Date]';
- },
-
- /**
- * 格式化日期
- * @param {Date|String} date 日期或日期字符串
- */
- formatDate(date) {
- let YYYY = null;
- let M = null;
- let MM = null;
- let D = null;
- let DD = null;
- let h = null;
- let hh = null;
- let m = null;
- let mm = null;
- let s = null;
- let ss = null;
- let ms = null;
- let ms2 = null;
- let ms3 = null;
- let ms4 = null;
- let dt = null;
-
- // 如果 date 是 String 类型
- if (date && this.isString(date)) {
- // 当前日期
- let dt = new Date();
-
- // 真机运行时,如果直接用 new Date('YYYY-MM-DD hh:mm:ss') 会报 Invalid Date 错误,所以采用下面的方式创建日期
- let dtArr = date.replace(/\//g, '.').replace(/-/g, '.').replace(/:/g, '.').replace(/T/g, ' ').replace(' ', '.').replace(
- 'Z', '').split('.');
- // 年
- if (dtArr.length > 0 && !isNaN(dtArr[0])) {
- dt.setFullYear(parseInt(dtArr[0]));
- }
- // 月
- if (dtArr.length > 1 && !isNaN(dtArr[1])) {
- dt.setMonth(parseInt(dtArr[1]) - 1);
- }
- // 日
- if (dtArr.length > 2 && !isNaN(dtArr[2])) {
- dt.setDate(parseInt(dtArr[2]));
- }
- // 时
- if (dtArr.length > 3 && !isNaN(dtArr[3])) {
- dt.setHours(parseInt(dtArr[3]));
- } else {
- dt.setHours(0);
- }
- // 分
- if (dtArr.length > 4 && !isNaN(dtArr[4])) {
- dt.setMinutes(parseInt(dtArr[4]));
- } else {
- dt.setMinutes(0);
- }
- // 秒
- if (dtArr.length > 5 && !isNaN(dtArr[5])) {
- dt.setSeconds(parseInt(dtArr[5]));
- } else {
- dt.setSeconds(0);
- }
- // 毫秒
- if (dtArr.length > 6 && !isNaN(dtArr[6])) {
- dt.setMilliseconds(parseInt(dtArr[6]));
- } else {
- dt.setMilliseconds(0);
- }
-
- date = dt;
- }
-
- // 如果 date 是 Date 类型
- if (date && this.isDate(date)) {
- YYYY = date.getFullYear();
- M = date.getMonth() + 1;
- MM = M >= 10 ? M : '0' + M;
- D = date.getDate();
- DD = D >= 10 ? D : '0' + D;
- h = date.getHours();
- hh = h >= 10 ? h : '0' + h;
- m = date.getMinutes();
- mm = m >= 10 ? m : '0' + m;
- s = date.getSeconds();
- ss = s >= 10 ? s : '0' + s;
- ms = date.getMilliseconds();
- ms2 = ms;
- ms3 = ms;
- ms4 = ms;
- if (ms < 10) {
- ms2 = '0' + ms;
- ms3 = '00' + ms;
- ms4 = '000' + ms;
- } else if (ms < 100) {
- ms3 = '0' + ms;
- ms4 = '00' + ms;
- } else {
- ms4 = '0' + ms;
- }
- }
-
- // 返回的数据对象
- let result = {
- YYYY: YYYY,
- MM: MM,
- M: M,
- DD: DD,
- D: D,
- hh: hh,
- h: h,
- mm: mm,
- m: m,
- ss: ss,
- s: s,
- ms: ms,
- ms2: ms2,
- ms3: ms3,
- ms4: ms4,
- dt: date,
- fmt1: `${YYYY}-${MM}-${DD}`,
- fmt2: `${YYYY}年${M}月${D}日`,
- fmt3: `${YYYY}-${M}-${D} ${hh}:${mm}`,
- fmt4: `${h}:${m}:${s}`,
- fmt5: `${MM}-${DD}`,
- fmt6: `${YYYY}-${MM}`,
- fmt7: `${YYYY}年${M}月`,
- fmt8: `${h}:${m}`,
- fmt9: `${M}月${D}日`,
- notes: 'YYYY(年),MM(月,补0),M(月,不补0),DD(日,补0),D(日,不补0),hh(时,补0),h(时,不补0),mm(分,补0),m(分,不补0),ss(秒,补0),s(秒,不补0),ms(毫秒,不补0),ms2(毫秒,补0到2位),ms3(毫秒,补0到3位),ms4(毫秒,补0到4位),其余的fmt1,fmt2,... 看格式就知道了!'
- };
- return result;
- }
- }
- };
- </script>
- <style lang="scss" scoped>
- .content {
- text-align: left;
- flex: 1;
- color: #101010;
- }
- .content.placeholder{
- color: #aeaeae;
- }
- .dis-fix{
- display: flex;
- justify-content: space-around;
- }
- </style>
|