1、效果展示
1.1、添加日程

1.2、顯示已添加了的日程,并且在日歷上標(biāo)注

1.3、點(diǎn)擊標(biāo)注,彈出日程內(nèi)容以及重要程度

2、需求分析
在新項(xiàng)目中,需要在首頁(yè)做個(gè)日歷展示以及實(shí)現(xiàn)添加,查看,修改,刪除日程的功能,ElementUI組件庫(kù)中有一個(gè)calendar組件可以拿來(lái)進(jìn)行復(fù)用。
3、后臺(tái)接口查看
一開(kāi)始后臺(tái)那邊沒(méi)有返回日期,在日歷上進(jìn)行標(biāo)注的過(guò)程必須是需要后臺(tái)那邊返回添加了日程的時(shí)間過(guò)來(lái)的,前端這邊再去將帶有日程的時(shí)間存進(jìn)一個(gè)數(shù)組,然后再去單獨(dú)渲染到日歷上去。

4、標(biāo)注渲染問(wèn)題的難點(diǎn)
這里可以有很多不同的方式去實(shí)現(xiàn)這個(gè)難點(diǎn),我這邊是和后臺(tái)開(kāi)發(fā)人員協(xié)商好,前端傳入年月給后臺(tái),然后后臺(tái)返回那一個(gè)月份所有添加了日程的數(shù)據(jù)給我,然后通過(guò)給上一個(gè)月以及下一個(gè)月添加點(diǎn)擊事件,通過(guò)事件的觸發(fā)來(lái)完成獲取年月的信息,從而調(diào)一次接口,拿到當(dāng)月的數(shù)據(jù)。
4、代碼實(shí)現(xiàn)過(guò)程
4.1、日歷的初步渲染
這里的calendar_nolabel類是沒(méi)有做標(biāo)注的時(shí)間部分,而calendar_label是做了標(biāo)注的部分
<el-calendar v-model="value" v-loading="loading" class="cal">
<template slot="dateCell" slot-scope="{ date, data }">
<p
v-if="handleSelected(data.day) == '1'"
class="calendar_nolabel"
@click="clickCalendar(data)"
>
{{ data.day.split("-").slice(2).join("-") }}
</p>
<p
v-if="handleSelected(data.day) == '2'"
class="calendar_label"
@click="clickCalendar(data)"
>
{{ data.day.split("-").slice(2).join("-") }}
</p>
</template>
</el-calendar>
4.2、添加日程按鈕
<el-button class="add-canlendar" @click="handleAdd">+ 添加日程</el-button>
4.3、封裝日程彈窗組件
這里有一點(diǎn)需要注意,在打開(kāi)的時(shí)候我添加了重置表單的操作,這里在使用重置的時(shí)候需要使用this.$nextTick(()=>{}),因?yàn)檫@一步操作需要在DOM渲染完成時(shí)去執(zhí)行。
<template>
<div class="canlendar">
<el-dialog :title="title" :visible.sync="dialogFormVisible">
<el-form :model="form" :rules="rules" ref="ruleForm">
<el-form-item
label="重要等級(jí)"
prop="level"
:label-width="formLabelWidth"
>
<el-select v-model="form.level" placeholder="請(qǐng)選擇">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item
label="日程日期"
prop="scheduleDate"
:label-width="formLabelWidth"
>
<el-date-picker
v-model="form.scheduleDate"
type="date"
format="yyyy-MM-dd"
placeholder="選擇日程日期"
>
</el-date-picker>
</el-form-item>
<el-form-item
label="日程內(nèi)容"
prop="content"
:label-width="formLabelWidth"
>
<el-input
type="textarea"
v-model="form.content"
autocomplete="off"
></el-input>
</el-form-item>
</el-form>
<div slot="footer" v-if="isAdd" class="dialog-footer">
<el-button @click="handleCancel">取 消</el-button>
<el-button type="primary" @click="handleDeterminer">確 定</el-button>
</div>
<div slot="footer" v-else-if="!isAdd" class="dialog-footer">
<el-button class="del-btn" @click="handleRemove">刪除日程</el-button>
<el-button type="primary" @click="handleClose">關(guān)閉</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { postAddSchedule, deleteSchedule } from "@/api/home";
export default {
data() {
return {
dialogFormVisible: false,
form: {},
formLabelWidth: "80px",
title: "",
scheId: "",
isAdd: true,
options: [
{
value: 1,
label: "一般",
},
{
value: 2,
label: "重要",
},
{
value: 3,
label: "很重要",
},
],
// 表單校驗(yàn)
rules: {
level: [{ required: true, message: "請(qǐng)輸入等級(jí)", trigger: "blur" }],
content: [{ required: true, message: "請(qǐng)輸入內(nèi)容", trigger: "change" }],
scheduleDate: [
{
type: "date",
required: true,
message: "請(qǐng)選擇日期",
trigger: "change",
},
],
},
};
},
methods: {
// 打開(kāi)彈窗
handleOpen(row) {
if (row) {
this.title = "查看日程";
//彈出日程信息
this.form = JSON.parse(JSON.stringify(row));
this.scheId = JSON.parse(JSON.stringify(row)).id;
this.isAdd = false;
} else {
this.title = "添加日程";
this.isAdd = true;
this.$nextTick(() => {
this.form = {};
this.$refs.ruleForm.resetFields();
});
}
this.dialogFormVisible = true;
},
// 刪除日程
handleRemove() {
// 寫(xiě)上你的刪除接口
});
},
handleClose() {
this.dialogFormVisible = false;
},
// 點(diǎn)擊取消
handleCancel() {
this.form = {};
this.$refs.ruleForm.resetFields();
this.dialogFormVisible = false;
},
// 點(diǎn)擊確定
handleDeterminer() {
this.$refs.ruleForm.validate((val) => {
if (val) {
// 寫(xiě)上你的添加日程的接口
this.dialogFormVisible = false;
} else {
this.dialogFormVisible = true;
}
});
},
},
};
</script>
4.4、添加子組件彈窗
將彈窗加入到日歷組件代碼中去,在日歷組件中通過(guò)獲取子組件的handleOpen()方法,彈出日程框。
- 引入組件
import AddCanlendar from "./canlendarDialog";
- 彈窗組件
<!-- 日程彈窗 -->
<AddCanlendar
ref="canlendarDialog"
@handleSuccess="handleSuccess"
></AddCanlendar>
4.5、開(kāi)始渲染當(dāng)月日程并做標(biāo)注
通過(guò)map遍歷,取每個(gè)元素節(jié)點(diǎn)下的日期,然后返回到一個(gè)新數(shù)組中去。
// 獲取當(dāng)月的日程信息
handleSchedule() {
// 將日期傳入接口,判斷當(dāng)前時(shí)間是否有日程
getScheduleList(this.moment(this.value).format("YYYY-MM"))
.then((res) => {
if (res.code == 0) {
// this.label.push(res.data);
this.label = res.data.map((item) => {
return item.scheduleDate;
});
this.notLabel = res.data;
this.loading = false;
}
})
.catch();
},
通過(guò)遍歷數(shù)組,判斷日期,有標(biāo)注的日程數(shù)組中有數(shù)據(jù)的話返回flag為2,否則就是默認(rèn)的1。這里可以繼續(xù)多重判斷,比如可以根據(jù)重要的等級(jí)程度去返回不同的值去做渲染。
handleSelected(day) {
let flag = "1";
this.label.forEach((item) => {
if (item == day) {
flag = "2";
return;
}
});
return flag;
},
4.6、給上一月,下一月按鈕添加點(diǎn)擊事件
created() {
this.$nextTick(() => {
// 點(diǎn)擊上個(gè)月
let prevBtn = document.querySelector(
".el-calendar__button-group .el-button-group>button:nth-child(1)"
);
prevBtn.addEventListener("click", () => {
this.value = this.moment(this.value).format("YYYY-MM");
console.info(this.value);
this.handleSchedule();
});
// 點(diǎn)擊今天
let currBtn = document.querySelector(
".el-calendar__button-group .el-button-group>button:nth-child(2)"
);
currBtn.addEventListener("click", () => {
this.value = this.moment(this.value).format("YYYY-MM");
console.info(this.value);
this.handleSchedule();
});
// 點(diǎn)擊下個(gè)月
let nextBtn = document.querySelector(
".el-calendar__button-group .el-button-group>button:nth-child(3)"
);
nextBtn.addEventListener("click", () => {
this.value = this.moment(this.value).format("YYYY-MM");
console.info(this.value);
this.handleSchedule();
});
});
},
5、完整代碼:
<template>
<div>
<el-calendar v-model="value" v-loading="loading" class="cal">
<template slot="dateCell" slot-scope="{ date, data }">
<p
v-if="handleSelected(data.day) == '1'"
class="calendar_nolabel"
@click="clickCalendar(data)"
>
{{ data.day.split("-").slice(2).join("-") }}
</p>
<p
v-if="handleSelected(data.day) == '2'"
class="calendar_label"
@click="clickCalendar(data)"
>
{{ data.day.split("-").slice(2).join("-") }}
</p>
</template>
</el-calendar>
<el-button class="add-canlendar" @click="handleAdd">+ 添加日程</el-button>
<!-- 日程彈窗 -->
<AddCanlendar
ref="canlendarDialog"
@handleSuccess="handleSuccess"
></AddCanlendar>
</div>
</template>
<script>
import AddCanlendar from "./canlendarDialog";
import { getScheduleList, deleteSchedule } from "@/api/home";
export default {
components: {
AddCanlendar,
},
data() {
return {
value: new Date(),
notLabel: [],
label: [],
loading: true,
};
},
computed: {},
created() {
this.$nextTick(() => {
// 點(diǎn)擊上個(gè)月
let prevBtn = document.querySelector(
".el-calendar__button-group .el-button-group>button:nth-child(1)"
);
prevBtn.addEventListener("click", () => {
this.value = this.moment(this.value).format("YYYY-MM");
console.info(this.value);
this.handleSchedule();
});
// 點(diǎn)擊今天
let currBtn = document.querySelector(
".el-calendar__button-group .el-button-group>button:nth-child(2)"
);
currBtn.addEventListener("click", () => {
this.value = this.moment(this.value).format("YYYY-MM");
console.info(this.value);
this.handleSchedule();
});
// 點(diǎn)擊下個(gè)月
let nextBtn = document.querySelector(
".el-calendar__button-group .el-button-group>button:nth-child(3)"
);
nextBtn.addEventListener("click", () => {
this.value = this.moment(this.value).format("YYYY-MM");
console.info(this.value);
this.handleSchedule();
});
});
},
mounted() {
this.handleSchedule();
console.log(this.label);
},
methods: {
// 添加日程
handleAdd() {
this.$refs.canlendarDialog.handleOpen();
},
// 添加成功
handleSuccess() {
// 添加日程成功后去刷新列表
this.handleSchedule();
},
handleSelected(day) {
let flag = "1";
this.label.forEach((item) => {
if (item == day) {
flag = "2";
return;
}
});
return flag;
},
// 獲取當(dāng)月的日程信息
handleSchedule() {
// 將日期傳入接口,判斷當(dāng)前時(shí)間是否有日程
getScheduleList(this.moment(this.value).format("YYYY-MM"))
.then((res) => {
if (res.code == 0) {
// this.label.push(res.data);
this.label = res.data.map((item) => {
return item.scheduleDate;
});
this.notLabel = res.data;
this.loading = false;
}
})
.catch();
},
// 點(diǎn)擊
clickCalendar(day) {
this.notLabel.forEach((item) => {
if (item.scheduleDate == day.day) {
// 展示日程
this.$refs.canlendarDialog.handleOpen(item);
}
});
},
},
};
</script>
<style scoped>
.cal ::v-deep.el-calendar-day .calendar_nolabel {
margin: 0 auto;
padding: 2px;
text-align: center;
}
.cal ::v-deep.el-calendar-day .calendar_label {
border: 1px solid #F93937;
border-radius: 50%;
width: 23px;
margin: 0 auto;
padding: 2px;
text-align: center;
}
.add-canlendar {
width: 90%;
height: 35px;
line-height: 13px;
background: #409eff;
color: #fff;
margin-top: 5px;
}
</style>