FullCalendar移动端:实现双击事件打开编辑模态框
FullCalendar移动端交互优化方案
问题场景
电脑端功能正常:鼠标悬停事件触发Tooltip显示,点击事件打开编辑模态框;但移动端点击事件时,Tooltip与编辑模态框会同时弹出,需求调整为移动端双击事件才打开编辑模态框。
原代码
JavaScript部分
document.addEventListener('DOMContentLoaded', function() { if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) { initialViews = 'dayGridMonth'; }else{ initialViews = 'dayGridMonth'; } var calendarEl = document.getElementById('calmanut'); var today = moment().day(); var calendar = new FullCalendar.Calendar(calendarEl, { headerToolbar: { left: 'prev,next today', center: 'title', right: 'dayGridMonth' }, locale: "pt-br", buttonText:{ today: 'Hoje', month: 'Mês', }, navLinks: true, firstDay: today, initialView: initialViews, editable: true, selectable: true, unselectAuto:true, eventOverlap: true, slotDuration: '00:30', allDaySlot : false, eventStartEditable: true, eventDurationEditable:false, longPressDelay: 0, nowIndicator: "true", expandRows: true, slotMinTime: '09:00', slotMaxTime: '18:00', contentHeight: 'auto', businessHours: { daysOfWeek: [ 1, 2, 3, 4, 5 ], }, eventDidMount: function (info) { $(info.el).popover({ title: info.event.title, placement: 'top', trigger: 'hover', content: 'Período: ' + info.event.groupId, container: 'body' }); }, events: [ { title: 'All Day Event', start: '2023-11-17' }, { title: 'Long Event', start: '2023-11-17', end: '2023-09-10', color: 'purple' // override! }, { groupId: '999', title: 'Repeating Event', start: '2023-11-17T16:00:00' }, { groupId: '999', title: 'Repeating Event', start: '2023-11-17T16:00:00' } ], eventClick: function(info) { var eventObj = info.event; tarperiod = eventObj.extendedProps.Tarefa; $('#ModalAddmanut1').modal("show"); $('#ModalAddmanut1 #sidtaref').val(eventObj.extendedProps.Id); $('#ModalAddmanut1 #titletar1').val(eventObj.extendedProps.Tarefa); $('#ModalAddmanut1 #cortaref1').val(eventObj.extendedProps.cor); }, }); calendar.render(); });
HTML部分
<link href="https://cdn.jsdelivr.net/npm/fullcalendar@5.9.0/main.min.css" rel="stylesheet"> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.1/moment.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/fullcalendar@5.9.0/main.min.js"></script> <script src="https://unpkg.com/tooltip.js/dist/umd/tooltip.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.6/umd/popper.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.bundle.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.min.js"></script> <div id='calmanut'></div> <div class="modal fade" tabindex="-1" id="ModalAddmanut1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false"> <div class="modal-dialog modal-lg" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="exampleModalLabel">ELIMINAR/ALTERAR PLANIFICAÇÃO DE TAREFAS</h5> <button type="button" class="btn-close atualvisita1" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <form method="POST" class="row g-3 instper1"> <input type="hidden" class="form-control" id="sidtaref" name="sidtaref"> <div class="row"> <div class="col-8"> <div class="form-group"> <label for="titletar1"> <strong>Tarefa</strong> </label> <select class="js-states form-control" name="titletar1" id="titletar1"> <option></option> <option>Teste</option> </select> </div> </div> </div> <div class="row"> <div class="col-6"> <div class="form-group"> <label for="cortaref1"> <strong>Cor</strong> </label> <select class="js-states form-control" name="cortaref1" id="cortaref1"> <option value=""></option> <option style="color:#000;" value="#F00">◼ Vermelho</option> <option style="color:#000;" value="#FFF">◼ Branco</option> </select> </div> </div> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fechar</button> <button type="button" class="btn btn-danger valtareff1" id="save-event">Eliminar</button> <button type="button" class="btn btn-primary valtareff" id="save-event">Alterar</button> </div> </div> </div> </div>
解决方案
核心修改点
- 统一设备类型判断,提取
isMobile变量 - 区分移动端与非移动端的Tooltip触发逻辑
- 为移动端实现双击触发模态框的交互逻辑
修改后的JavaScript代码
document.addEventListener('DOMContentLoaded', function() { // 统一判断移动端设备 const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); const initialViews = 'dayGridMonth'; // 简化原有重复赋值逻辑 const calendarEl = document.getElementById('calmanut'); const today = moment().day(); const calendar = new FullCalendar.Calendar(calendarEl, { headerToolbar: { left: 'prev,next today', center: 'title', right: 'dayGridMonth' }, locale: "pt-br", buttonText:{ today: 'Hoje', month: 'Mês', }, navLinks: true, firstDay: today, initialView: initialViews, editable: true, selectable: true, unselectAuto:true, eventOverlap: true, slotDuration: '00:30', allDaySlot : false, eventStartEditable: true, eventDurationEditable:false, longPressDelay: 0, nowIndicator: "true", expandRows: true, slotMinTime: '09:00', slotMaxTime: '18:00', contentHeight: 'auto', businessHours: { daysOfWeek: [ 1, 2, 3, 4, 5 ], }, eventDidMount: function (info) { $(info.el).popover({ title: info.event.title, placement: 'top', // 移动端用focus触发Tooltip,非移动端用hover trigger: isMobile ? 'focus' : 'hover', content: 'Período: ' + info.event.groupId, container: 'body' }); }, events: [ { title: 'All Day Event', start: '2023-11-17' }, { title: 'Long Event', start: '2023-11-17', end: '2023-09-10', color: 'purple' }, { groupId: '999', title: 'Repeating Event', start: '2023-11-17T16:00:00' }, { groupId: '999', title: 'Repeating Event', start: '2023-11-17T16:00:00' } ], eventClick: function(info) { const eventObj = info.event; const $eventEl = $(info.el); if (!isMobile) { // 非移动端直接打开编辑模态框 openEditModal(eventObj); return; } // 移动端双击检测逻辑:300ms内连续点击两次视为双击 const now = Date.now(); const lastClickTime = $eventEl.data('lastClickTime') || 0; if (now - lastClickTime < 300) { // 触发双击事件,打开模态框 openEditModal(eventObj); $eventEl.data('lastClickTime', 0); } else { // 第一次点击,仅触发Tooltip并记录点击时间 $eventEl.focus(); $eventEl.data('lastClickTime', now); // 超时未触发第二次点击则重置计时 setTimeout(() => { $eventEl.data('lastClickTime', 0); }, 300); } }, }); calendar.render(); // 抽离模态框打开逻辑,提高代码复用性 function openEditModal(eventObj) { tarperiod = eventObj.extendedProps.Tarefa; $('#ModalAddmanut1').modal("show"); $('#ModalAddmanut1 #sidtaref').val(eventObj.extendedProps.Id); $('#ModalAddmanut1 #titletar1').val(eventObj.extendedProps.Tarefa); $('#ModalAddmanut1 #cortaref1').val(eventObj.extendedProps.cor); } });
效果说明
- 非移动端:保持原有交互,鼠标悬停显示Tooltip,点击打开模态框
- 移动端:第一次点击仅显示Tooltip,300ms内第二次点击才打开编辑模态框,避免误触
内容的提问来源于stack exchange,提问作者Bruno
相关产品推荐
相关产品推荐

