需求:點擊按鈕后,將設定的一些信息插入到系統日歷的日程安排中。
調研過程
- 先google了一段時間,了解該需求大概的實現方式。可以創建日歷文件,在點擊的時候下載該日歷文件,看起來還比較復雜,并且由于不具備系統日歷相關的知識,擔心純手寫造成的bug難以解決,所以放棄了。
- 在npm上搜索了相關的插件,發現了add-to-calendar-button,看文檔發現適配了很多平臺上的日歷,但是真正使用后發現無法滿足需求,這個插件不支持配置日程中url。并且在第三方軟件中也出現了打不開的bug,所以放棄了這個插件。但是在調試的過程中發現在android設備上或ios非safari的瀏覽器是無法直接插入系統日歷的,而是下載日歷ics文件自行導入。
- 既然知道了不同系統以及瀏覽器中的效果都不一樣,那就只能想一個滿足需求的同時還提高用戶體驗的辦法了。我的項目是海外的,所以用safari和google瀏覽器的用戶居多,并且也了解到需求方主要是要用ios日歷提醒。
- 主動和產品溝通,ios用戶保障在safari瀏覽器中插入系統日歷,除開safari以外的用戶(包含android/其它瀏覽器/第三方app內置瀏覽器)點擊按鈕后跳轉google日歷。
- 又去npm找生成ics文件的插件,發現了ics.js,配置項挺多的也滿足需求。google日歷官方給出的方式需要注冊appKey,但是ai告訴我有另一種方式:跳轉url并傳參,但是google日歷找不到參數文檔,不過主要的信息也都可以寫入。
源代碼
封裝公共方法,點擊按鈕后調用addCalendar
import moment from 'moment';
import { createEvent } from 'ics';
import { getBrowser } from '@/utils/common';/*** 添加谷歌日歷* @param {Object} event - 日歷事件對象
*/
const addGoogleCalendar = (event) => {const startDate = moment(event.start).format('YYYYMMDD[T]HHmmss');const endDate = moment(event.end).format('YYYYMMDD[T]HHmmss');const params = new URLSearchParams({action: 'TEMPLATE',text: event.name,dates: `${startDate}/${endDate}`,details: `${event.url}\n${event.description}`,ctz: event.timezone || 'Asia/Tokyo'});const googleUrl = `https://calendar.google.com/calendar/render?${params.toString()}`;console.log(decodeURIComponent(googleUrl));window.open(googleUrl, '_blank');
}/*** 為 Safari 用戶創建并下載 ICS 文件* @param {Object} event - 日歷事件對象
*/
const createICSEvent = (event) => {const filename = `${event.name}.ics`;const startMoment = moment.utc(event.start).local();const endMoment = moment.utc(event.end).local();const icsEvent = {start: [startMoment.year(),startMoment.month()+1,startMoment.date(),startMoment.hour(),startMoment.minute()],end: [endMoment.year(),endMoment.month()+1,endMoment.date(),endMoment.hour(),endMoment.minute()],title: event.name,description: `${event.url}\n${event.description}`,url: event.url,alarms: [{action: 'display',description: 'Reminder',trigger: { ...event.reminder, before: true }}]};createEvent(icsEvent, (error, value) => {if (error) {console.log(error);return;}if (!value) return;const file = new File([value], filename, { type: 'text/calendar' });const link = document.createElement('a');const url = URL.createObjectURL(file);link.href = url;link.download = filename;document.body.appendChild(link);link.click();document.body.removeChild(link);URL.revokeObjectURL(url);});
}/*** 添加日歷* @param {Object} params - 日歷參數* @param {string} params.name - 日歷事件名稱* @param {number} params.start - 日歷事件開始時間* @param {number} params.end - 日歷事件結束時間* @param {string} params.url - 日歷事件 URL* @param {string} params.description - 日歷事件描述(備注)
*/
export const addCalendar = (params) => {const finalParams = {...params,timezone: 'Asia/Tokyo',reminder: { hours: 1 }}const { isSafari } = getBrowser();if (isSafari) {createICSEvent(finalParams);} else {addGoogleCalendar(finalParams);}
}
相關文檔
- stack overflow上關于google日歷參數的回答
- ics.js
- add-to-calendar-button