实现在h5中添加日历提醒:safari唤起系统日历,其它浏览器跳转google日历

**需求:**点击按钮后,将设定的一些信息插入到系统日历的日程安排中。

调研过程

  1. 先google了一段时间,了解该需求大概的实现方式。可以创建日历文件,在点击的时候下载该日历文件,看起来还比较复杂,并且由于不具备系统日历相关的知识,担心纯手写造成的bug难以解决,所以放弃了。
  2. 在npm上搜索了相关的插件,发现了add-to-calendar-button, 看文档发现适配了很多平台上的日历,但是真正使用后发现无法满足需求,这个插件不支持配置日程中url。并且在第三方软件中也出现了打不开的bug,所以放弃了这个插件。但是在调试的过程中发现在android设备上或ios非safari的浏览器是无法直接插入系统日历的,而是下载日历ics文件自行导入。
  3. 既然知道了不同系统以及浏览器中的效果都不一样,那就只能想一个满足需求的同时还提高用户体验的办法了。我的项目是海外的,所以用safari和google浏览器的用户居多,并且也了解到需求方主要是要用ios日历提醒。
  4. 主动和产品沟通,ios用户保障在safari浏览器中插入系统日历,除开safari以外的用户(包含android/其它浏览器/第三方app内置浏览器)点击按钮后跳转google日历。
  5. 又去npm找生成ics文件的插件,发现了ics.js,配置项挺多的也满足需求。google日历官方给出的方式需要注册appKey,但是ai告诉我有另一种方式:跳转url并传参,但是google日历找不到参数文档,不过主要的信息也都可以写入。

源代码

封装公共方法,点击按钮后调用addCalendar

javascript 复制代码
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);
  }
}

相关文档

  1. stack overflow上关于google日历参数的回答
  2. ics.js
  3. add-to-calendar-button
相关推荐
程序员Sunday2 小时前
JavaScript 事件循环面试题,宏任务与微任务怎么执行|Sunday面试指南
开发语言·javascript·面试·校招·事件循环·程序员sunday
Setsuna_F_Seiei3 小时前
前端转型 Agent 开发 06 之 Agent Memory 记忆系统(让 Agent 更智能,更懂你)
前端·agent·ai编程
志尊宝3 小时前
Vue3 零基础每日笔记(073):keep-alive 页面缓存实战——列表页返回不丢状态
vue.js·笔记·缓存·#vue #前端 #前端开发·#javascript·#vue.js
zhangzeyuaaa3 小时前
Ruby 多线程、GVL(GIL)与 Mutex 完全指南
开发语言·前端·ruby
默_笙4 小时前
🌊 向量库和 ES 都查不出"关系",我只好给奶茶建了一张人脉网
前端·javascript
优选资讯4 小时前
标签打印软件怎么对接 Excel 数据
前端·excel
思无邪665 小时前
用 AI 做 JS 逆向:从抓包到复现的完整方法论
开发语言·javascript·人工智能
一个风轻云淡5 小时前
GCC 和 GDB命令简单解读
java·linux·前端
u0111026756 小时前
图片处理接口如何统一错误信息 前端提示与后端错误码设计
前端·状态模式
福兮说6 小时前
浏览器里把 iPhone 的 HEIC 转成 JPG:Chrome 解不开、转完大了七成、拍摄时间全丢,六个坑实测
前端·javascript·图像处理·chrome·ios·iphone·heic