废话不多说,直接上图上代码,主要看周日历生成的逻辑(代码还不够简洁,自己使用时候可以优化下,看懂了逻辑可以参考此逻辑改写成 Angular,React组件,根据自己项目需要修改相应的字段即可)
效果图
用法
<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 | 一周的开始时间 | number | 0-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>