自定义时间选择器组件

<template>
  <view class="ccq-week-picker">
    <view class="ccq-week-popup_header">
      <text class="cancel" @click="onCancel">取消</text>
      <text class="title">选择时间</text>
      <text class="sure" @click="onSure">确定</text>
    </view>
    <view class="typeList">
      <view
        class="typeItem"
        v-for="(item, index) in typeList"
        :key="item.value"
        :class="{ on: type === item.value }"
        @click="changeType(index)"
        >{{ item.name }}</view
      >
      <!--      <u-subsection :list="typeList" :current="formatType" @change="changeType"></u-subsection>-->
    </view>
    <view class="valueBox">
      <view v-if="type !== 'custom'">{{ checkval }}</view>
      <view class="valueBox-custom" v-else>
        <view
          class="startTime customTime"
          :class="{ on: editTimeKey === 0, customtext: !formatTime(result[0]) }"
          @click="changeCustom(0)"
        >
          {{ formatTime(result[0]) || " 请选择开始时间 " }}
        </view>
        <view>-</view>
        <view
          class="endTime customTime"
          :class="{ on: editTimeKey === 1, customtext: !formatTime(result[1]) }"
          @click="changeCustom(1)"
        >
          {{ formatTime(result[1]) || " 请选择结束时间 " }}
        </view>
      </view>
    </view>

    <picker-view
      :value="pickerValue"
      @change="bindChange"
      class="ccq-week-picker_view"
      indicatorStyle="height: 80rpx;"
      @pickstart="pickStart"
      @pickend="pickEnd"
    >
      <picker-view-column class="ccq-week-picker_item years">
        <view
          class="ccq-week-picker_item_view"
          :style="{ height: height + 'px' }"
          v-for="(item, index) in years"
          :key="index"
          >{{ item }}年</view
        >
      </picker-view-column>
      <picker-view-column
        class="ccq-week-picker_item months"
        v-if="type !== 'week'"
      >
        <view
          class="ccq-week-picker_item_view"
          :style="{ height: height + 'px' }"
          v-for="(item, index) in months"
          :key="index"
          >{{ index + 1 }}月</view
        >
      </picker-view-column>
      <picker-view-column
        class="ccq-week-picker_item days"
        v-if="(type === 'day' || type === 'custom' || type === 'oldday')&&showDays"
      >
        <view
          class="ccq-week-picker_item_view"
          :style="{ height: height + 'px' }"
          v-for="(item, index) in days"
          :key="index"
          >{{ index + 1 }}日</view
        >
      </picker-view-column>
      <picker-view-column
        class="ccq-week-picker_item weeks"
        v-if="type === 'week'"
      >
        <view
          class="ccq-week-picker_item_view"
          :style="{ height: height + 'px' }"
          v-for="(item, index) in weeks"
          :key="index"
          >{{ index + 1 }}周</view
        >
      </picker-view-column>
    </picker-view>
  </view>
</template>

<script>
import dayjs from "dayjs";
import weekOfYear from "dayjs/plugin/weekOfYear";
import isoWeeksInYear from "dayjs/plugin/isoWeeksInYear";
import isoWeek from "dayjs/plugin/isoWeek";
import isLeapYear from "dayjs/plugin/isLeapYear";
dayjs.extend(isLeapYear);
dayjs.extend(isoWeek);
dayjs.extend(weekOfYear);
dayjs.extend(isoWeeksInYear);
const nowDate = new Date();
var yesterTime = new Date().getTime();
var yesterTimeStamp = new Date(yesterTime);
var month = yesterTimeStamp.getMonth(); //昨天的月
var day = yesterTimeStamp.getDate(); //昨天的日
//昨天的日期20220630
var yesterday =
  yesterTimeStamp.getFullYear() +
  "" +
  (yesterTimeStamp.getMonth() > 9
    ? yesterTimeStamp.getMonth() + 1
    : "0" + (yesterTimeStamp.getMonth() + 1)) +
  "" +
  (yesterTimeStamp.getDate() > 9
    ? yesterTimeStamp.getDate()
    : "0" + yesterTimeStamp.getDate());
export default {
  name: "ccq-week-picker",
  props: {
    value: {
      type: String,
      default: "",
    },
    currentType: {
      type: String,
      default: "day",
    },
    typeList: {
      type: Array,
      default: () => {
        return [
          { name: "今日", value: "day" },
          { name: "昨日", value: "oldday" },
          { name: "本周", value: "week" },
          { name: "本月", value: "month" },
          { name: "自定义", value: "custom" },
        ];
      },
    },
    /**
     * 格式化
     * 0:  2021-06-01
     * 1:  2021年06月01日
     */
    formatType: {
      type: Number,
      default: 0,
    },
    // 列的高度
    height: {
      type: [Number, String],
      default: 50,
    },
    // 自定义类型时 日期最大跨度  默认30天
    customMax: {
      type: [Number],
      default: 30,
    },
	//是否解除30天限制
	unfreeze:{
		type:Boolean,
		default:false
	}
  },
  data() {
    return {
      years: [],
      months: 12,
      days: 30,
      weeks: 52,
      pickerValue: [0, 0, 0],
      result: [],
      type: "",
      editTimeKey: 0,
      record: [], //选择过的日期记录
      isMoveing: false,
      showDays:true,
      update:0,
    };
  },
  watch: {
    pickerValue(newValue) {
      //监听控制可选择范围
      if (this.pickerValue[0] == 0) {
        //当选择最新一年时
        this.months = new Date().getMonth() + 1;
        if (this.type == "day" || this.type === "oldday") {
          //按日时  可选当天
          // 当前结果日期
          const currentValue = this.result[0].split("-");
          if (
            new Date().getFullYear() == currentValue[0] &&
            new Date().getMonth() + 1 == currentValue[1]
          ) {
            //同年当月
            this.days = new Date().getDate();
          } else {
            this.days = dayjs(this.result[0]).daysInMonth();
          }
        }
        if (this.type == "custom") {
          //按自定义时  控制日最大值
          if (this.pickerValue[1] + 1 == new Date().getMonth() + 1) {
            this.days = new Date().getDate();
          } else {
            if ([1, 3, 5, 7, 8, 10, 12].includes(this.pickerValue[1] + 1)) {
              this.days = 31;
            } else if ([4, 6, 9, 11].includes(this.pickerValue[1] + 1)) {
              this.days = 30;
            } else if (this.pickerValue[1] + 1 === 2) {
              this.days = new Date().getFullYear() % 4 ? 28 : 29;
            }
          }
        }
        if (this.type == "week") {
          //最新一年的周最大值
          if (dayjs().day() == 1) {
            //明天测
            this.weeks = dayjs().isoWeek();
          } else {
            this.weeks = dayjs().isoWeek();
          }
        }
      } else {
        if (
          this.type == "day" ||
          this.type == "custom" ||
          this.type == "oldday"
        ) {
          this.days = dayjs(this.result[0]).daysInMonth();
        }
        this.months = 12;
        this.weeks = 52;
      }
      this.showDays = true
    },
  },
  computed: {
    checkval() {
      //计算返回日期格式
      if (this.type === "day" || this.type == "oldday") {
        let weekWord = ["日", "一", "二", "三", "四", "五", "六"];

        let oldyesterTime = new Date().getTime() - 24 * 60 * 60 * 1000;
        let oldyesterTimeStamp = new Date(oldyesterTime);
        //昨天的日期20220630
        let oldyesterday =
          oldyesterTimeStamp.getFullYear() +
          "" +
          (oldyesterTimeStamp.getMonth() > 9
            ? oldyesterTimeStamp.getMonth() + 1
            : "0" + (oldyesterTimeStamp.getMonth() + 1)) +
          "" +
          (oldyesterTimeStamp.getDate() > 9
            ? oldyesterTimeStamp.getDate()
            : "0" + oldyesterTimeStamp.getDate());

        if (this.result[0] == dayjs().format("YYYY-MM-DD")) {
          return `${dayjs(this.result[0]).format("YYYY年MM月DD日")} (今日)`;
        } else if (this.result[0] == dayjs(oldyesterday).format("YYYY-MM-DD")) {
          return `${dayjs(this.result[0]).format("YYYY年MM月DD日")} (昨日)`;
        } else {
          return `${dayjs(this.result[0]).format("YYYY年MM月DD日")} (周${
            weekWord[dayjs(this.result[0]).day()]
          })`;
        }
      } else if (this.type === "week") {
        return `${dayjs(this.result[0]).format("YYYY年")}${
          this.pickerValue[1] + 1
        }周 ${dayjs(this.result[0]).format("MM月DD日")}-${dayjs(
          this.result[1]
        ).format("MM月DD日")}`;
      } else if (this.type === "month") {
        return `${dayjs(this.result[0]).format("YYYY年MM月")} ${dayjs(
          this.result[0]
        ).format("MM月DD日")}-${dayjs(this.result[1]).format("MM月DD日")}`;
      }
      return dayjs().format("YYYY-MM-DD");
    },
  },
  created() {
    this.$nextTick(() => {
      this.type = this.currentType;
      console.log(this.type, "类型");
      this.dateInit();
    });
  },
  methods: {
    pickStart() {
      this.isMoveing = true;
    },
    pickEnd() {
      this.isMoveing = false;
    },
    //添加日期选择记录
    addRecord(item) {
      var record = JSON.parse(JSON.stringify(this.record));
      record = record.filter((e) => {
        return e.type != item.type;
      });
      record.unshift(item);
      this.record = record;
    },
    async dateInit() {
      this.$set(this.pickerValue, 0, 0);
      //初始化 控制选择范围
      var date = yesterday;
      if (this.type == "oldday") {
        date = dayjs().subtract(1, "days").format("YYYYMMDD");
      }
      if (this.type == "day") date = dayjs().format("YYYYMMDD");
      let v = dayjs(date).format("YYYY-MM-DD").split("-");
      let s = Number(v[0]) - 50;
      let e = Number(v[0]);
      let y = Number(v[0]),
        y_index;
      let m = Number(v[1]);

      // 年
      let arr = []
      for (let i = s; i <= e; i++) {
        if (i == y) {
          //所选年的index
          y = i;
          y_index = e - s - (e - y);
        }
        arr.unshift(i);
      }
      this.years = arr

      // 月
      for (let i = 1; i <= 12; i++) {
        if (i == Number(m)) {
          //所选月的index
          m = i;
          break;
        }
      }
      this.$set(this.pickerValue, 1, dayjs(date).month());
      if ([1, 3, 5, 7, 8, 10, 12].includes(dayjs(date).month())) {
        this.days = 31;
      } else if ([4, 6, 9, 11].includes(dayjs(date).month())) {
        this.days = e % 4 ? 29 : 28;
      } else if (dayjs(date).month() === 2) {
        this.days = e % 4 ? 29 : 28;
      }
      this.$set(this.pickerValue, 2, dayjs(date).date() - 1);
      this.result = [
        dayjs(date).format("YYYY-MM-DD"),
        dayjs(date).format("YYYY-MM-DD"),
      ];
      const pickerValueCopy = JSON.parse(JSON.stringify(this.pickerValue));
      this.pickerValue = [];
      this.$nextTick(() => {
        this.pickerValue = pickerValueCopy;
      });
    },
    //选择日期类型
    changeType(index) {
      let type = this.typeList[index].value;
      if (this.type === type) return;
      this.type = type;
      if (type === "day") {
        this.dateInit();
      } else if (type === "oldday") {
        this.dateInit();
      } else if (type === "week") {
        this.pickerValue = [0, dayjs().isoWeek() - 1];
        this.result = [
          dayjs().startOf("isoWeek").format("YYYY-MM-DD"),
          dayjs().format("YYYY-MM-DD"),
        ];
      } else if (type === "month") {
        this.pickerValue = [0, dayjs().month()];
        this.result = [
          dayjs().startOf("month").format("YYYY-MM-DD"),
          dayjs().format("YYYY-MM-DD"),
        ];
      } else {
        this.pickerValue = [0, dayjs().month(), dayjs().date() - 1];
      }
      this.editTimeKey = 0;
    },
    // 自定义切换
    changeCustom(key) {
      if (this.editTimeKey === key) return;
      // this.showDays = false
      this.editTimeKey = key;
      let date = this.result[key].split('-')
      let years = 0
      this.years.forEach((val,index)=>{
        if(val==date[0]){
          years = index
        }
      })
      let result = [years,date[1] - 1,date[2] - 1]

      // this.$nextTick(()=>{
      //   setTimeout(()=>{
          this.pickerValue = result
      //   },300)
      // })
    },
    formatWord(num) {
      return num > 9 ? `${num}` : `0${num}`;
    },
    formatTime(time) {
      return time ? dayjs(time).format("YYYY年MM月DD日") : "";
    },
    // picker change
    //选择日期
    bindChange: function (e) {
      let v = e.detail.value;
      this.pickerValue = v;
      //限定日的选择范围
      if (this.type !== "week" && this.type !== "month") {
        if ([1, 3, 5, 7, 8, 10, 12].includes(v[1] + 1)) {
          this.days = 31;
        } else if (v[1] + 1 === 2) {
          this.days = this.years[v[0]] % 4 ? 29 : 28;
        } else {
          this.days = 30;
        }
        if (this.days < v[2] + 1) v[2] = this.days - 1;
      }
      if (this.type === "day" || this.type === "oldday") {
        this.result = [
          `${this.years[v[0]]}-${this.formatWord(v[1] + 1)}-${this.formatWord(
              v[2] + 1
          )}`,
          `${this.years[v[0]]}-${this.formatWord(v[1] + 1)}-${this.formatWord(
              v[2] + 1
          )}`,
        ];
      } else if (this.type === "week") {
        var selectWeek = v[1] + 1; //第几周
        const today = dayjs().format("YYYY-MM-DD");
        const firstDayOfWeek = dayjs()
            .isoWeek(selectWeek)
            .startOf("isoWeek")
            .format("YYYY-MM-DD");
        let endDayOfWeek = dayjs()
            .isoWeek(selectWeek)
            .endOf("isoWeek")
            .format("YYYY-MM-DD");
        if (today === endDayOfWeek) {
          endDayOfWeek = today;
        }
        this.result = [firstDayOfWeek, endDayOfWeek];
      } else if (this.type === "month") {
        let time = `${this.years[v[0]]}-${this.formatWord(v[1] + 1)}`;
        this.result = [
          dayjs(time).startOf("month").format("YYYY-MM-DD"),
          dayjs(time).endOf("month").format("YYYY-MM-DD"),
        ];
      } else if (this.type === "custom") {
        let time = `${this.years[v[0]]}-${this.formatWord(v[1] + 1)}-${this.formatWord(v[2] + 1)}`;
        this.result[this.editTimeKey] = time;
        if (this.editTimeKey == 1) {
          //调整自定义--结束时间时
          if (dayjs(this.result[0]).isAfter(dayjs(this.result[1]))) {
            this.result[0] = dayjs(this.result[1]).subtract(this.customMax, "day").format("YYYY-MM-DD");
          } else {
            if (-1 * dayjs(this.result[0]).diff(dayjs(this.result[1]), "day") >= this.customMax + 1) {
              //选择开始时间  发现与结束时间相差大于31天时

              this.$nextTick(() => {
                this.result[0] = dayjs(this.result[1])
                    .subtract(this.customMax, "day")
                    .format("YYYY-MM-DD");
                this.update++ // 更新视图
              })
            }
          }
        } else {
          //调整自定义--开始时间时
          if (dayjs(this.result[0]).isAfter(dayjs(this.result[1]))) {
            if (dayjs().isBefore(dayjs(dayjs(this.result[0]).add(this.customMax, "day").format("YYYY-MM-DD")))) {
              //增加30天后的日期大于今天
              this.result[1] = dayjs().subtract(1, "day").format("YYYY-MM-DD");
            } else {
              this.result[1] = dayjs(this.result[0]).add(this.customMax, "day").format("YYYY-MM-DD");
            }
          }
          else {
            if (dayjs(this.result[1]).diff(dayjs(this.result[0]), "day") >= this.customMax + 1) {
              //选择开始时间  发现与结束时间相差大于31天时
              this.result[1] = dayjs(this.result[0]).add(this.customMax, "day").format("YYYY-MM-DD");
            }
          }
        }
      }
      this.addRecord({
        type: this.type,
        result: this.result,
        pickerValue: this.pickerValue,
      });
    },
    // 取消
    onCancel() {
      this.$emit("cancal");
    },
    // 确认
    onSure() {
      if (this.isMoveing) {
        return;
      }
      if (this.type === "custom") {
        if (!this.result[0] || !this.result[1]) {
          return;
        }
        if (dayjs(this.result[0]).isAfter(dayjs(this.result[1]))) {
          return;
        }
      }
      this.$nextTick(() => {
        this.$emit("change", this.result, this.type, this.checkval);
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.ccq-week-picker {
  background-color: #ffffff;
  .typeList {
    display: flex;
    justify-content: space-between;
    padding: 24rpx;
    .typeItem {
      padding: 14rpx 32rpx;
      border-radius: 8rpx;
      border: 2rpx solid #dcdcdc;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    .on {
      font-size: 26rpx;
      font-family: PingFangSC-Semibold, PingFang SC;
      font-weight: 600;
      color: #19b691;
      line-height: 36rpx;
      background: #e9faf3;
      border-radius: 8rpx;
      border: 2rpx solid #19b691;
    }
  }
  .valueBox {
    font-size: 28rpx;
    font-family: PingFangSC-Semibold, PingFang SC;
    font-weight: 600;
    color: rgba(0, 0, 0, 0.9);
    line-height: 44rpx;
    display: flex;
    justify-content: center;
    align-items: center;
    .valueBox-custom {
      display: flex;
      align-items: center;
      justify-content: center;
      .startTime {
        margin-right: 24rpx;
      }
      .endTime {
        margin-left: 24rpx;
      }
      .customTime {
        font-size: 28rpx;
        font-family: PingFangSC-Regular, PingFang SC;
        font-weight: 400;
        color: rgba(0, 0, 0, 0.9);
        line-height: 44rpx;
        width: 318rpx;
        height: 64rpx;
        background: #f3f3f3;
        border-radius: 8rpx;
        display: flex;
        justify-content: center;
        align-items: center;
      }
      .customtext {
        // color: rgba(0,0,0,.26);
      }
      .on {
        background-color: $u-type-primary-c;
        color: rgba(0, 0, 0, 0.6);
      }
    }
  }
}

.ccq-week-popup_header {
  width: 100%;
  height: 112rpx;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 42rpx;
  border-bottom: 1rpx solid #e7e7e7;
  .cancel {
    font-size: 32rpx;
    font-family: PingFangSC-Medium, PingFang SC;
    font-weight: 500;
    color: rgba(0, 0, 0, 0.6);
    line-height: 48rpx;
  }
  .title {
    font-size: 32rpx;
    font-family: PingFangSC-Semibold, PingFang SC;
    font-weight: 600;
    color: rgba(0, 0, 0, 0.9);
    line-height: 48rpx;
  }
  .sure {
    font-size: 32rpx;
    font-family: PingFangSC-Semibold, PingFang SC;
    font-weight: 600;
    color: #19b691;
    line-height: 48rpx;
  }
}

.ccq-week-popup-text {
  font-size: 32rpx;

  &.cancel {
    color: rgba(0, 0, 0, 0.6);
  }

  &.sure {
    color: #1ab592;
  }
}

.ccq-week-picker_view {
  width: 100%;
  height: 500rpx;
}

.ccq-week-picker_item {
  display: flex;
  align-items: center;
  justify-content: center;

  &.years {
    flex: 1;
  }

  &.months {
    flex: 1;
  }

  &.weeks {
    flex: 1;
  }
}

.ccq-week-picker_item_view {
  font-size: 28rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}
</style>

需要下载dayjs

页面使用:

	<u-popup v-model="showScreen" border-radius="16" mode="bottom" height="800rpx">
			<weekPicker :customMax="3600" :unfreeze="true" @change="changeTypeOption" @cancal="showScreen = false"
				ref="weekPicker">
			</weekPicker>
		</u-popup>

显示时间:

<view style="padding: 24rpx 0 0 24rpx;font-size: 32rpx;line-height: 48rpx;font-weight: 600;"
							@click="showScreen = true">{{showDate}}
							<text class="fwhfont icon-icon-caret-down" style="font-size: 40rpx;"></text>
						</view>
		// 日期变化
			changeTypeOption(arr, type, checkval) {
				console.log(arr, type, checkval);
				var now = new Date();
				var selectDate = '';
				if (type === 'day') {
					selectDate = checkval.substr(5, checkval.length);
				}
				if (type === 'week') {
					selectDate = checkval.substr(5, checkval.length);
				}
				if (type === 'month') {
					selectDate = checkval;
					if (dayjs(arr[1]).isBefore(dayjs(dayjs(now).format('YYYY-MM-DD')))) { //选择的月底日期在今天之前为true
					} else {
						let nowYear = now.getFullYear();
						let nowMonth = now.getMonth() + 1 > 9 ? now.getMonth() + 1 : '0' + (now.getMonth() + 1);
						let nowDate = now.getDate();
						arr[1] = nowYear + '-' + nowMonth + '-' + (nowDate > 9 ? nowDate : '0' + nowDate);
					}
				}
				if (type === 'custom') {
					selectDate = arr[0] + '-' + arr[1];
				}
				this.showScreen = false;
				this.typeSelect = type;
				this.checkval = checkval;
				this.typeOption = arr
				let stimer = (new Date(arr[0]).getTime() / 1000) + ''
				console.log(stimer, 'stimer', new Date('2023-06-26').getTime());
				this.sTime = type === 'day' ? '' : stimer;
				let etimer = new Date(arr[1])
				etimer.setHours(24, 0, 0, 0)
				this.eTime = type === 'day' ? '' : (etimer.getTime() / 1000) + '';
				this.showDate = this.getShowDate();
				this.currPage = 0;
				this.Backup()
				this.getDouTypeCouponList()
			},
			getShowDate() {
				if (this.typeSelect === 'day') {
					let weekWord = ['日', '一', '二', '三', '四', '五', '六'];
					if (!Number(this.checkval.substr(0, 4))) {
						//默认当天日期
						var nowDay = dayjs().format('YYYYMMDD');
						return nowDay.substr(4, 2) + '月' + nowDay.substr(6, 2) + '日' + '(今日)';
					}
					if (Number(this.checkval.substr(0, 4)) < currentDate.getFullYear()) {
						return this.checkval;
					} else {
						return this.checkval.substring(5); //.substr(5,this.checkval.length)
					}
				} else if (this.typeSelect === 'oldday') {
					return this.checkval.substring(5);
				} else if (this.typeSelect === 'week') {
					return this.checkval;
				} else if (this.typeSelect === 'month') {
					return this.checkval;
				} else if (this.typeSelect === 'custom') {
					var dateArr =
						this.typeOption[0].substr(0, 4) +
						'年' +
						this.typeOption[0].substr(5, 2) +
						'月' +
						this.typeOption[0].substr(8, 2) +
						'日' +
						'-' +
						(this.typeOption[0].substr(0, 4) == this.typeOption[1].substr(0, 4) ? '' : this.typeOption[1]
							.substr(0, 4) + '年') +
						this.typeOption[1].substr(5, 2) +
						'月' +
						this.typeOption[1].substr(8, 2) +
						'日';
					return dateArr;
				}
			},

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值