分享這套功能齊全,視覺超級可愛還有響應式變化,教學文件又很容易閱讀的套件 Evo Calendar。
當初在製作 JS side project 時,想找一個與 VCalendar 視覺相近的套件,但多半都不合意。六角學院指派的 side project 教練也幫我找了另一個純 JS 的範例,也很接近 VCalendar,但我實在改不動它的 JS,專題完成時間有限,所以最後仍選擇使用套件製作專題。

evocalendar
一、官網資源
evocalendar 官網:https://edlynvillegas.github.io/evo-calendar/
二、CDN 安裝
需搭配 jQuery 使用
<!-- 月曆 evo-calendar -->
<script src="https://www.jsdelivr.com/package/npm/evo-calendar"></script>
<!-- Add jQuery library (required) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script>
<!-- Add the evo-calendar.js for.. obviously, functionality! -->
<script src="https://cdn.jsdelivr.net/npm/evo-calendar@1.1.2/evo-calendar/js/evo-calendar.min.js"></script>
三、使用範例
https://codepen.io/annchou_illu/pen/MWLrNqw
3-1. 目標功能
- 建立行事曆,可填寫事件標題
- 可填寫開始與結束時間
- 分類活動
- 登記是否為重複活動
- 寫點敘述文字
3-2. 示範步驟
- 規劃版位
- 準備事件來源資料
3-3. 實作
- 規劃版位
<div class="container">
<!-- 表格區 -->
<form class="form">
<div>
<label for="name">活動標題</label>
<input type="text" placeholder="活動標題" class="event-input">
</div>
<div>
<label for="startDate">開始時間</label>
<input type="date" class="event-input">
</div>
<div>
<label for="endDate">結束時間</label>
<input type="date" class="event-input">
</div>
<div>
<label for="type">活動類型</label>
<select name="type" id="type" class="event-input">
<option value="">--Please choose an option--</option>
<option value="event">event</option>
<option value="holiday">holiday</option>
</select>
</div>
<div>
<label for="everyYear">是否每年重覆</label>
<select name="everyYear" id="everyYear" class="event-input">
<option value="">--Please choose an option--</option>
<option value="yes">yes</option>
<option value="no">no</option>
</select>
</div>
<div>
<label for="describe">敘述</label>
<textarea name="describe" id="describe" cols="20" rows="10" class="event-input"></textarea>
</div>
<button type="button" class="addEvent">送出</button>
</form>
<!-- 月曆渲染區 -->
<div id="calendar" style="width:600px"></div>
</div>
- 觀察套件所需資料格式
進入 evocalendar 的 GitHub 閱讀文件,在 event 處可以看到它接受的資料格式。所以我們可得知資料格式為:
(1)外層陣列包裹多個物件資料
(2)物件屬性務必要有 id、name、date、type
- 準備事件來源資料庫用於渲染月曆
const events = [
{
id: "E001",
name: "看牙醫",
description: "記得先刷牙",
date: "2023/12/05",
type: "event",
everyYear: false
},
...略
];
- 初始化月曆
官網已經都幫我們寫好了,直接 copy paste。別忘了注意剛才 HTML 的月曆渲染 element id 要和這裏設定的相同。
$('#calendar').evoCalendar({
settingName: settingValue
})
- 月曆設定
填入自己想顯示的視覺元件和設定。其實能做的選擇不多,它的原始預設是月份選擇、月曆、事件列表都全部打開的,但我們可以在此根據能分配給月曆顯示的區域尺寸,選擇哪些元件預設為隱藏狀態。
$("#calendar")
.evoCalendar({
format: "yyyy/mm/dd", //時間格式
todayHighlight: true, //標註今天
sidebarDisplayDefault: false, //左側月份預設顯示狀態
eventDisplayDefault: false, //右側事件預設顯示狀態
calendarEvents: events //傳入套件的事件來源
})
- 完成以上動作,就可以呈現月曆資料了

Demo
- 綁定畫面左側,用來增加事件的 DOM 元素們
這裡小偷懶一點,輸入格的 DOM 綁定在所有輸入格上,但實際上還是一格格使用唯一的 class 或 id 綁定比較好。
// 綁定送出按鈕
const btnAddEvent = document.querySelector(".addEvent");
// 綁定所有輸入格
const eventInput = document.querySelectorAll(".event-input");
// 綁定表單
const form = document.querySelector(".form");
// 當送出按鈕按下,觸發 addEvent 函式
btnAddEvent.addEventListener("click", addEvent);
function addEvent(){}
- 撰寫建立事件函式
function addEvent
在這個函式中,我們需要
(1)取得輸入格中填入的資料
(2)在月曆上新增事件:在官網的 methods 中,可以找到 addCalendarEvent 方法
(3)新增事件後要再次初始化月曆,更新渲染
(4)新增成功後清除輸入格中的資料
function addEvent() {
// 取得輸入格資料
const data = {
id: new Date().getTime(), // 因為 id 是唯一值,直接用日期當作唯一值
name: eventInput[0].value,
description: eventInput[5].value,
date: [eventInput[1].value, eventInput[2].value],
type: eventInput[3].value,
everyYear: eventInput[4].value === "yes" ? true : false
};
// 測試印出要新增的資料,看是否符合格式
console.log(data);
// 在月曆上新增事件
$("#calendar").evoCalendar("addCalendarEvent", data);
// 執行月曆初始化
$("#calendar").evoCalendar();
// 清除表單,因為我的表格在 HTML 中最外層有使用 form 包裹,才能使用這個辦法
form.reset();
}
- 加入必填驗證
所有輸入格必填,否則無法送出資料。
新增一個函式function checkFormError
,它的職責是驗證每個輸入格均有填寫,如果有內容為""
空字串,則變更變數isFilledForm
的狀態,使用alert
提醒,並返回結果給function addEvent
。function addEvent
內部最前面則加入執行驗證的程式碼,如果有未填欄位則使用return
中斷函式執行。
function addEvent() {
// 有未填欄位就跳出
if (!checkFormError()) {
return;
}
const data = ...略
}
// 確認表格必填
function checkFormError() {
let isFilledForm = true;
eventInput.forEach((item) => {
if (item.value.trim() === "") {
isFilledForm = false;
}
});
alert("欄位均須填寫");
return isFilledForm;
}
- 延伸
$("#calendar")
.evoCalendar({
...略
})
.on("selectEvent", function (event, activeEvent) {
// 點擊月曆右側的事件列才會觸發
console.log("你選擇的事件是", event);
})
.on("selectDate", function (event, activeDate) {
// 點擊月曆日期會觸發
console.log(
"你選擇的事件 id 是",
event.target.evoCalendar.$active.events[0].id
);
console.log(`你選擇的日期是:${activeDate}`);
})
.on("selectMonth", function (event, activeMonth) {
// 點擊月曆月份會觸發
console.log(`你選擇的月份是:${activeMonth}`);
});
四、心得
- 功能齊全,文件說明清楚,但比較適合顯示範圍整頁時使用。
a. 顯示範圍過小時,RWD 會跑版,這可以靠客製化解決,但不容易魔改
b. 因為左右按鈕是換年份,不是換月份,必須叫出左邊的月份側邊欄才能換月,這是他的 UX 比較不好的地方 - 視覺可愛,但 CSS 比較不好更動,覆蓋權重較難
- 雖然功能齊全又漂亮,但作者似乎沒有再繼續維護,真的很可惜