自定义一个三级联动年月日时间选择器

基于picker-view 封装的 vue3 uniapp小程序


image.png
<!-- 自定义三级联动日期选择器 -->
<template>
  <view>
    <view class="header">
      <view
        :class="dataType=='start'?'data choose':'data'"
        @click="chooseData('start')"
      >{{ start?start:'开始日期' }}</view>
      <view class="heng"></view>
      <view
        :class="dataType=='end'?'data choose':'data'"
        @click="chooseData('end')"
      >{{ end?end:'结束日期'}}</view>
    </view>
    <view class="picker-box">
      <picker-view
        indicator-class="indicatorClass"
        mask-class="mask-class"
        :indicator-style="indicatorStyle"
        :value="valueIndex"
        @change="bindChange"
        class="picker-view"
      >
        <picker-view-column class="view-column first">
          <view
            v-for="(item,index) in years"
            :key="index"
            class="item"
            :class=" valueIndex[0] ==  index ? 'choose' : ' ' "
          >{{item}}</view>
        </picker-view-column>
        <picker-view-column>
          <view
            v-for="(item,index) in months"
            :key="index"
            class="item"
            :class=" valueIndex[1] ==  index ? 'choose' : ' ' "
          >{{item}}</view>
        </picker-view-column>
        <picker-view-column class="view-column third">
          <view
            v-for="(item,index) in days"
            :key="index"
            class="item"
            :class=" valueIndex[2] ==  index ? 'choose' : ' ' "
          >{{item}}</view>
        </picker-view-column>
      </picker-view>
    </view>
  </view>
</template>

<script setup>
import { ref, reactive, toRefs, onBeforeMount, onMounted, watch } from "vue";

onBeforeMount(() => {});
onMounted(() => {
  getDay();
  valueIndex.value = [
    years.value.indexOf(year.value),
    months.value.indexOf(month.value),
    days.value.indexOf(day.value)
  ];
});
const props = defineProps({
  newDay: {
    type: Number
  }
});

//监听重置
watch(
  () => props.newDay,
  (newVal, oldVal) => {
    if (newVal) {
      start.value = null;
      end.value = null;
      dataType.value = "";
      year.value = date.getFullYear();
      month.value = date.getMonth() + 1;
      day.value = date.getDate();
      getDay();
      valueIndex.value = [
        years.value.indexOf(year.value),
        months.value.indexOf(month.value),
        days.value.indexOf(day.value)
      ];
    }
  }
);

const start = ref(null);
const end = ref(null);
const dataType = ref("");
const emit = defineEmits(["changeData"]);

//点击选择与回显
const chooseData = type => {
  dataType.value = type;
  if (type == "start") {
    console.log(start.value, "start.value");
    if (start.value) {
      valueIndex.value = [
        years.value.indexOf(+start.value.split("-")[0]),
        months.value.indexOf(+start.value.split("-")[1]),
        days.value.indexOf(+start.value.split("-")[2])
      ];
    } else {
      console.log(year.value, month.value, day.value);
      start.value = `${year.value}-${month.value}-${day.value}`;
    }
  } else if (type == "end") {
    if (end.value) {
      valueIndex.value = [
        years.value.indexOf(+end.value.split("-")[0]),
        months.value.indexOf(+end.value.split("-")[1]),
        days.value.indexOf(+end.value.split("-")[2])
      ];
      console.log(valueIndex.value, "?????valueIndex.value");
    } else {
      end.value = `${year.value}-${month.value}-${day.value}`;
    }
  }
  emit("changeData",start.value,end.value);
};

const bindChange = e => {
  valueIndex.value = e.detail.value; // 注意这行一定要加上,否则判断的两个索引的值永远不会相等
  const val = e.detail.value;
  year.value = years.value[val[0]];
  month.value = months.value[val[1]];
  day.value = days.value[val[2]];
  if (dataType.value == "start") {
    start.value = `${year.value}-${month.value}-${day.value}`;
  } else if (dataType.value == "end") {
    end.value = `${year.value}-${month.value}-${day.value}`;
  }
  getDay();
};

//日期时间
const date = new Date();
const years = ref([]);
const months = ref([]);
const days = ref([]);
const year = ref([]);
const month = ref([]);
const day = ref([]);
const valueIndex = ref([]);
const indicatorStyle = ref(`height: 50px;`);

//获取当前年月日
year.value = date.getFullYear();
month.value = date.getMonth() + 1;
day.value = date.getDate();

for (let i = 1990; i <= date.getFullYear(); i++) {
  years.value.push(i);
}

for (let i = 1; i <= 12; i++) {
  months.value.push(i);
}

//定义每月的天数,不定义渲染会出问题
for (let i = 1; i <= 31; i++) {
  days.value.push(i);
}

//定义每月的天数
const getDay = () => {
  let dayNum = 31;
  switch (month.value) {
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12:
      break;
    case 4:
    case 6:
    case 9:
    case 11:
      dayNum = 30;
      break;
    case 2:
      if (
        (year.value % 4 == 0 && year.value % 100 != 0) ||
        year.value % 400 == 0
      ) {
        dayNum = 29;
      } else {
        dayNum = 28;
      }
      break;
  }
  days.value = [];
  for (let i = 1; i <= dayNum; i++) {
    days.value.push(i);
  }
};
</script>
<style lang='scss' scoped>
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  .data {
    width: 315rpx;
    height: 72rpx;
    background: #f6f7f8;
    font-family: PingFang SC-Regular;
    font-size: 28rpx;
    color: #7a7f88;
    line-height: 72rpx;
    text-align: center;
  }
  .choose {
  }
  .heng {
    width: 24rpx;
    height: 2rpx;
    background: #c9cdd4;
  }
}

//选择器样式
.picker-box {
  width: 100%;
  height: 240rpx;
  overflow: hidden;
}
::v-deep .indicatorClass {
  width: 100%;
  height: 80rpx !important;
  line-height: 80rpx;
  background: #eaf7f3;
  z-index: 0; //避免文字被覆盖;
}
.picker-view {
  width: 100%;
  height: 360rpx;
  margin-top: 20rpx;
}
.item {
  height: 80rpx;
  line-height: 80rpx;
  text-align: center;
  font-size: 32rpx;
}
.choose {
}

//给中间选中行添加border-radius
::v-deep .view-column.third .indicatorClass {
  border-radius: 0 8rpx 8rpx 0;
}
::v-deep .view-column.first .indicatorClass {
  border-radius: 8rpx 0 0 8rpx;
}

// 修改原有的上下边框颜色
::v-deep .indicatorClass::after {
  border-bottom: 0rpx solid #fff;
}
::v-deep .indicatorClass::before {
  border-top: 0rpx solid #fff;
}

//设置蒙层样式
::v-deep .mask-class {
  //   background: #000;
  background-image: linear-gradient(
      rgba(255, 255, 255, 0.8),
      rgba(255, 255, 255, 0)
    ),
    // linear-gradient(rgba(255, 0, 0, 0.6), rgba(255, 255, 255, 0));
}
</style>

使用:

   <my-time :open="openTime" v-if="openTime" @sub="subTime" :timeData="timeData" @close="closeTime"/>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容