仿element时间选择器 选择周范围

最近需求出现 周维度选择范围,常用的element不支持周类型 下面是写了一个dome供大家参考
组件库用到moment 处理时间  element【popover】  语言vue2
 <el-popover
    placement="bottom"
    width="650"
    @show="popoverShow"
    @hide="hide"
    ref="popoverRef"
    trigger="click">
    <div  class="picker-box">
         <div class="picker-top"><div @click="minusYear"><i class="el-icon-arrow-left"></i> </div> <div>{{  year   }}</div><div @click="addYear"><i class="el-icon-arrow-right"></i></div></div>
         <div class="picker-content">
          <!--  oneState? 选中的第一个: highlight ? 选中的中间高亮 : 无-->
          <div @click="selectWeeks(item)" 
          @mouseenter="handleMouseEnter(item)" 
          v-for="(item, index) in weeksData" 
          :class="item.oneState || item.twoState ? 'one-state-box' : item.highlight ? 'highlight-box' :''" 
          :key="index" class="weeks-block">
          <!-- item.isCurrent ? 当前周高亮 : 其他周 -->
          <span :class=" item.isCurrent ? 'current-week' : ''">第{{ item.weekNumber }}周 <br>
                {{ item.start }}~{{ item.end }} 
              </span>
          </div>
         </div>
    </div>
    <div slot="reference" class="popover-slot-box">
       <i class="el-icon-date" style="line-height: 34px;"></i> <div style="width: 130px; text-align: center;">{{ value1[0] ? $moment(value1[0].startState).format('YYYY-MM-DD') + '第' + value1[0].weekNumber + '周' : '开始日期' }}</div><span style="color: 303133;"></span><div style="width: 130px; text-align: center;">{{ value1[1] ? $moment(value1[1].endState).format('YYYY-MM-DD') + '第' + value1[1].weekNumber + '周' : '结束日期'  }}</div>
    </div>
  </el-popover>
<script>
   export default {
    data () {
      return {
        year: moment().format("YYYY"),  // 当前年份
        value1: [], // 存储选中的日期
        weeksData: [], //  存储页面展示 周
      }
    },
    created() {
        // 根据年份 获取到所有的周
     this.getAllWeeksOfYear(this.year)
    },
    methods: {
       // 减一年
      minusYear() {
        // 对年份进行减1
        this.year = moment(this.year).add(-1, 'y').format("YYYY")
        // 获取减去年 所有的周
        this.getAllWeeksOfYear(this.year)
        // 公共方法 处理高亮问题  选择跨年数据 需要用到
        this.HighlightFunc()
      },
      // 加一年
      addYear() {
         // 对年份进行减 加1
        this.year = moment(this.year).add(1, 'y').format("YYYY")
        // 获取增加年 所有的周
        this.getAllWeeksOfYear(this.year)
         // 公共方法 处理高亮问题  选择跨年数据 需要用到
        this.HighlightFunc()
   
      },
      // 获取全年周
      getAllWeeksOfYear(year) {
        const currentMoment = moment(); // 获取的年份 
  const weeks = [];
  const totalWeeks = moment().year(year).isoWeeksInYear(); // 全年周数
  for (let week = 1; week <= totalWeeks; week++) {
    const start = moment().year(year).isoWeek(week).startOf('isoWeek');
    const end = moment().year(year).isoWeek(week).endOf('isoWeek');
    // 判断当前周(精确到日期范围)
    const isCurrent = currentMoment.isBetween(start,  end, null, '[]'); 
    weeks.push({ 
      weekNumber: week,
      start: start.format('MM-DD'), 
      end: end.format('MM-DD'), 
      startState: start.format('YYYY-MM-DD'),
      endState: end.format('YYYY-MM-DD'),
      oneState: false, // 首次点击
      twoState: false, // 二次点击
      highlight: false, // 是否高亮
      isCurrent: isCurrent // 是否是当前周
    });
  }
  this.weeksData = weeks
},
      // 选择数据
      selectWeeks(item) {
        // 已经满足了 日期选择 再次选择做重置 处理
        if (this.value1.length == 2) {
          this.value1 = []
          this.weeksData.forEach((item) => {
            item.oneState = false
            item.twoState = false
            item.highlight = false
          })
        }
        // 默认push 数据
        this.value1.push(item)
        // 根据长度进行判断 1 还是 2
        if (this.value1.length == 1) {
          item.oneState = true
        } 
        if (this.value1.length == 2) {
          item.twoState = true
        } 
        // 长度等于2 等于已经选择完成
        if (this.value1.length == 2) {
        return  this.$refs.popoverRef.doClose()
        }
      },
      // 找到 开始高亮结尾高亮
      HighlightFunc() {
        this.weeksData.forEach((item) => {
           if (this.value1[0].startState == item.startState) {
            item.oneState = true
           }
           if (this.value1[1].startState == item.startState) {
            item.twoState = true
           }
        })
        if (this.value1.length == 2) {
            // 高亮 中间块 进行高亮
          this.handleMouseEnter(this.value1[1], true)
        }
      },
      // 鼠标移入
      handleMouseEnter(row, state = false) {
        if (this.value1.length == 1 || state) {
          let startState = this.value1[0].startState
          this.weeksData.forEach((item) => {
            // 进项判断 大于 小于  根据我的启示日期 进行判断
            if (startState <= row.startState) {
              if ((startState <= item.startState) && item.startState <= row.startState) {
              item.highlight = true
            } else {
              item.highlight = false
            }
            }
               // 进项判断 大于 小于  根据我的启示日期 进行判断
            if (startState >= row.startState) {
              if ((startState >= item.startState) && item.startState >= row.startState) {
              item.highlight = true
            } else {
              item.highlight = false
            }
            }
          }) 
        }
      // console.log('鼠标移入',e , item);
    },
    // 检测关闭是否选择完整
    hide() {
      if (this.value1.length != 2) {
        this.value1 = [] // 赋值自己的默认值
      }
    },
    // 周数据框 展开
    popoverShow() {
      if (this.value1.length == 2) {
        // 处理默认高亮
        this.HighlightFunc()
      }
    },
}
 }
</script>
.popover-slot-box {
  border: 1px solid #dcdfe6;
  color: #c0c4cc;
  display: flex;
  width: 350px;
  height: 36px;
  line-height: 36px;
  padding: 0 10px;
  box-sizing: border-box;
  font-size: 13px;
}

.picker-box {
  color: #606266;

  .picker-top {
    display: flex;
    justify-content: space-between;
  }

  .picker-content {
    display: flex;
    flex-wrap: wrap;

    .current-week {
      color: #409eff;
      font-weight: 700;
    }

    .one-state-box {
      background: #409eff;
      color: #fff !important;
    }

    .highlight-box {
      background: #f2f6fc;
    }

    .weeks-block {
      font-size: 12px;
      width: 81px;
      height: 40px;
      text-align: center;
      cursor: pointer;
      padding-top: 5px;
      box-sizing: border-box;
    }

    .weeks-block:hover {
      color: #409eff;
    }
  }
}

 

posted @ 2025-02-20 18:12  樱桃树下的约定  阅读(60)  评论(0)    收藏  举报
返回顶端