vue基于 Element UI封装的周日历组件

1,388 阅读1分钟

废话不多说,直接上图上代码,主要看周日历生成的逻辑(代码还不够简洁,自己使用时候可以优化下,看懂了逻辑可以参考此逻辑改写成 Angular,React组件,根据自己项目需要修改相应的字段即可)

效果图

image.png

用法

<script>
  import WeekCalendar from "@/components/YuTong/WeekCalendar";

  <WeekCalendar
    :firstDayOfWeek="0"
    @dateChange="dateChange"
    :dataSource="weekDataSource"
  >
    <template slot="dateCell" slot-scope="{ data }">
      <p>
        {{ data }}
      </p >
    </template>
  </WeekCalendar>
  export default {
    data() {
      return {
        weekDataSource: [
        {
          monday: "这是垃圾1",
          tuesday: "这是垃圾2",
          wednesday: "这是垃圾3",
          thursday: "这是垃圾4",
          friday: "这是垃圾5",
          saturday: "这是垃圾6",
          sunday: "这是垃7",
        },
      ],
      };
    }
  }
</script>

Attributes

参数说明类型可选值默认值
firstDayOfWeek一周的开始时间number0-6, 0是周日,1是周一,依次类推)1
dataSource要渲染的数据array
dateChange月份和周数的选择事件function(object)

slot

slot="dateCell" slot-scope="{ data }   用于自定义渲染单元格

注意事项:dataSource有时候需要将接口返回的数据结构在父组件处理成组件需要的结构,要么前端处理,要么后端处理好返回,前端处理方法参考以下

// 处理接口返回的“周”的数据 data:接口数据
    dealWeekData(data) {
      let list = [];
      if (!_.isEmpty(data)) {
        // 首先找到data中数组长度最大那个;
        const maxLen = _.maxBy(data, "dataSize");
        const maxData = maxLen.data;
        for (let k = 0; k < maxData.length; k++) {
          let objSource = {
            monday: "",
            tuesday: "",
            wednesday: "",
            thursday: "",
            friday: "",
            saturday: "",
            sunday: "",
          };
          for (let j = 0; j < data.length; j++) {
            let item = data[j];
            let itemData = data[j].data;
            const week = item.week;
            const it = itemData[k] ? itemData[k] : {};
            const name = it.activityName || "";
            const newName = name ? `${k + 1}. ${name}` : "";
            let obj={};
            if (week === 1) {
              obj = { monday: newName };
            } else if (week === 2) {
              obj = {  tuesday: newName };
            } else if (week === 3) {
              obj = { wednesday: newName };
            } else if (week === 4) {
              obj = {  thursday: newName };
            } else if (week === 5) {
              obj = { friday: newName };
            } else if (week === 6) {
              obj = {  saturday: newName };
            } else if (week === 7) {
              obj = { sunday: newName };
            }
            objSource={...it,...objSource,...obj}
          }
          list.push(objSource);
        }
      }
      return list;
    }
html部分
<template>
  <div>
    <div>
      <el-date-picker
        v-model="dateVal"
        @change="monthChange"
        type="month"
        placeholder="选择月"
        class="datepick"
      >
      </el-date-picker>
      <el-select
        :value="weekVal"
        placeholder="选择周"
        style="width: 240px"
        @change="weekChange"
        v-bind="$attrs"
        v-on="$listeners"
        class="week-select"
      >
        <el-option
          v-for="week in weekList"
          :key="week.value"
          :label="week.label"
          :value="week.value"
        />
      </el-select>
    </div>

    <div class="wk-table-top">
      <el-table :data="dataSource" border style="width: 100%">
        <el-table-column
          v-for="dt in dayTableData"
          :key="dt.dayNum"
          prop="monday"
          :label="dt.weekName"
        >
          <template slot-scope="scope">
            <slot name="dateCell" :data="scope.row"></slot>
          </template>
        </el-table-column>
      </el-table>
    </div>
  </div>
</template>
script 部分
<script>
import _ from "lodash";
import dayJs from "dayjs";
const weekTableHead = [
  ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
  ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
  ["周二", "周三", "周四", "周五", "周六", "周日", "周一"],
  ["周三", "周四", "周五", "周六", "周日", "周一", "周二"],
  ["周四", "周五", "周六", "周日", "周一", "周二", "周三"],
  ["周五", "周六", "周日", "周一", "周二", "周三", "周四"],
  ["周六", "周日", "周一", "周二", "周三", "周四", "周五"],
];
export default {
  name: "WeekCalendar",
  model: {
    prop: "value",
    event: "selectChange",
  },
  props: {
    dataSource: {
      type: Array,
      default: () => [],
    },
    firstDayOfWeek: {
      type: Number,
      default: 1,
    },
  },
  data() {
    return {
      options: [],
      dateVal: new Date(),
      weekVal: "1",
      weekList: [],
      dayTableData: [],
      daysArr: [],
    };
  },
  created() {
    const today = new Date();
    this.dateVal = today;
    this.weekVal = `${this.getMonthWeek().getWeek}`;
    const param = {
      year: today.getFullYear(),
      month: today.getMonth() + 1,
    };
    this.weekList = this.setWeeks(param.year, param.month);

    this.daysArr = this.getMonthAllDays(param, this.firstDayOfWeek) || [];
    this.dayTableData = this.daysArr[this.weekVal - 0 - 1];
    console.log(this.dayTableData, this.weekList);
    this.$emit("dateChange", this.dealDataForBack());
  },
  methods: {
    monthChange(val) {
      const year = val.getFullYear();
      const month = val.getMonth() + 1;
      this.dateVal = val;
      this.weekVal = "1";
      this.weekList = this.setWeeks(year, month);
      const daysArrs =
        this.getMonthAllDays({ year, month }, this.firstDayOfWeek) || [];
      this.daysArr = daysArrs;

      this.dayTableData = daysArrs[0];
      this.$emit("dateChange", this.dealDataForBack());
    },

    weekChange(val) {
      const id = val - 0 - 1;
      this.weekVal = val;
      this.dayTableData = this.daysArr[id];
      this.$emit("dateChange", this.dealDataForBack());
    },

    dealDataForBack() {
      const weekIdNum = this.weekVal - 0 - 1;
      const newArr = this.daysArr[weekIdNum];
      return {
        date: this.dateVal,
        week: this.weekVal,
        ...this.getWeekSAndE(newArr, this.dateVal),
        daysArr: newArr,
      };
    },

    getdaysArr() {
      let today = new Date();
      let y = today.getFullYear();
      let m = today.getMonth() + 1;
      const daysArrs = this.getMonthAllDays({ y, m }, 1) || [];
      const weekIdNum = this.getMonthWeek().getWeek - 1;
      const newArr = daysArrs[weekIdNum];
      const { firstDay, lastDay } = this.getWeekSAndE(newArr, new Date());
      return {
        daysArr: newArr,
        firstDay,
        lastDay,
      };
    },
    getMonthWeek() {
      let today = new Date();
      let a = today.getFullYear();
      let b = today.getMonth();
      let c = today.getDate();
      var date = new Date(a, b, c),
        w = date.getDay(),
        d = date.getDate();
      if (w == 0) {
        w = 7;
      }
      var config = {
        getMonth: date.getMonth() + 1,
        getYear: date.getFullYear(),
        getWeek: Math.ceil((d + 6 - w) / 7),
      };
      return config;
    },

    getMonthAllDays(ymd, firstDayOfWeek) {
      const date = new Date();
      //获取天数
      const year = ymd.year || date.getFullYear(); //年
      const month = ymd.month || date.getMonth() + 1; //月

      let date2 = new Date(year, month, 0);
      let days = date2.getDate(); // 本月有多少天

      //本月第一天是星期几
      date2.setDate(1);
      let day = date2.getDay(); // 本月第一天是星期几
      let list = [];
      for (let i = 0; i < days + day; i++) {
        let dayNum = i - day + 1 + firstDayOfWeek;

        list.push({ dayNum, content: "" });
      }
      const data = this.getTwoDimensional(list,year,month,days,firstDayOfWeek);
      return data;
    },

    // 将每月的天数按7天一组分割
    getTwoDimensional(list, year, month, days, firstDayOfWeek) {
      let twoDimensionArr = _.chunk(list, 7);
      let twoDimLength = twoDimensionArr.length;
      let to = 7 - twoDimensionArr[twoDimLength - 1].length;
      let nextMonth = month;
      let nextYear = year;
      let preMoth = month;
      let preYear = year;
      // 循环尾部补空格
      for (let i = 0; i < to; i++) {
        const last = twoDimensionArr[twoDimLength - 1];
        const len = last.length;
        const lastNum = last[len - 1].dayNum;
        twoDimensionArr[twoDimLength - 1].push({
          dayNum: lastNum + 1,
          content: "",
        });
      }

      for (let i = 0; i < twoDimensionArr.length; i++) {
        const item = twoDimensionArr[i];
        for (let j = 0; j < item.length; j++) {
          let weekName = "";
          let dateWeek = "";
          let isInNowMonth = true;
          let dayJ = item[j].dayNum;
          if (dayJ <= 0) {
            // dayJ <= 0 代表 dayJ是上个月的日期
            preMoth = month - 1;
            if (preMoth < 1) {
              preYear = year - 1;
              preMoth = 12;
            }
            let dateObj = new Date(preYear, preMoth, 0);
            let preMothDays = dateObj.getDate(); // 上月有多少天
            let newDayJ = preMothDays + dayJ;
            item[j].dayNum = newDayJ;
            dateWeek = `(${preMoth}/${newDayJ})`;
            weekName = `${weekTableHead[firstDayOfWeek][j]}(${preMoth}/${newDayJ})`;

            isInNowMonth = false;
          } else if (dayJ - days > 0) {
            // (dayJ - days) >= 0 代表 dayJ是下个月的日期
            nextMonth = month + 1;
            if (nextMonth > 12) {
              nextYear = year + 1;
              nextMonth = 1;
            }
            let newDayJ = dayJ - days;
            item[j].dayNum = newDayJ;
            dateWeek = `(${nextMonth}/${newDayJ})`;
            weekName = `${weekTableHead[firstDayOfWeek][j]}(${nextMonth}/${newDayJ})`;

            isInNowMonth = false;
          } else if (dayJ > 0 && dayJ - days <= 0) {
            dateWeek = `(${month}/${dayJ})`;
            weekName = `${weekTableHead[firstDayOfWeek][j]}(${month}/${dayJ})`;
            isInNowMonth = true;
          }
          item[j].week = j + 1;
          item[j].weekName = weekName;
          item[j].dateWeek = dateWeek;
          item[j].isInNowMonth = isInNowMonth;
        }
      }

      return twoDimensionArr;
    },

    // 取出当前选择月份的每周的第一天和最后一天

    getWeekSAndE(arr, dateVal) {
      const inMonthArr = _.filter(arr, (item) => item.isInNowMonth) || [];
      const dateStr = dayJs(dateVal).format("YYYY-MM");
      const firstDay = `${dateStr}-${inMonthArr[0].dayNum}`;
      const lastDay = `${dateStr}-${inMonthArr[inMonthArr.length - 1].dayNum}`;
      return { firstDay, lastDay };
    },

    // 判断某月共有几周
    getHowManyWeeks(y, m, d) {
      let date = new Date(y, m - 1, d);
      let funD = date.getDate();
      let weekendCount = 0;
      for (let i = 0; i < funD; i++) {
        date.setDate(i + 1);
        if (date.getDay() === 0) {
          weekendCount++;
        }
        if (i === funD - 1 && date.getDay() !== 0) {
          weekendCount += 1;
        }
      }

      return weekendCount;
    },

    setWeeks(year, month) {
      let weekList = [];
      let last = new Date(year, month, 0);
      let y = last.getFullYear();
      let m = last.getMonth() + 1;
      let d = last.getDate();
      let num = this.getHowManyWeeks(y, m, d) - 0;
      for (let i = 0; i < num; i++) {
        weekList.push({
          value: `${i + 1}`,
          label: `第${i + 1}周`,
        });
      }
      return weekList;
    },

    formatDayNum(day) {
      if (day < 10 && day > 0 && _.toString(day).length < 2) {
        return `0${day}`;
      } else {
        return `${day}`;
      }
    },
  },
};
</script>
style 部分
<style lang="scss" scoped>
.wk-table-top {
  margin-top: 20px;
}
.datepick {
  margin-right: 20px;
}
</style>