如何在 fullCalendar 中隐藏事件?

How to hide events in fullCalendar?

使用最新版本的 fullCalendar (5.3.2) 我想隐藏一些事件,这些事件对应于我现在不想在给定视图中显示的资源。执行此操作的标准方法是使用 eventClassNames 函数来检查它并添加“隐藏”class。像这样:

eventClassNames: function(arg) {
   my_class = "";
   if (arg.view.type != 'resourceTimeGridDay') {
      if (arg.event.extendedProps.real_rc != "1") {
         my_class = 'hidden';
      }
   }
   return my_class;
}

使用简单的 CSS:

.fc-event.hidden {
  display: none;
}

这工作正常,但当隐藏事件和显示事件之间存在重叠时会出现问题。例如在这种情况下:

events: [
  {
    title: 'Resource 1',
    real_rc: '1',
    start: '2020-12-22 16:00',
    end: '2020-12-22 17:00'
  },
  {
    title: 'Resource 2',
    real_rc: '2',
    start: '2020-12-22 15:00',
    end: '2020-12-22 17:00'
  }
]

只显示带有 real_rc == 1 的事件,事实上它是正确的,但是隐藏事件使用的 space 被保留,正如您在这张图片中看到的:

如果带有 real_rc: 2 的事件在 event 列表中被忽略,结果是预期的:

我已经使用 Chrome DevTools 试图弄清楚发生了什么,我认为问题是 'hidden' class 没有设置在“最外层的事件元素上" 作为 the fullCalendar states,但对于内部的:

(第一个 DIV 是第一个事件,如您所见,hidden class 已设置但不是 DIV,而是 a标签)

Here is a codepen to test it.

恕我直言,这是一个 fullCalendar 错误,但现在我遇到了问题,我需要一个解决方案。我的选择是:

  1. 为父级使用 CSS 选择器 <-- 不可能:它不存在(还)
  2. 做 (1) 使用 jquery <-- 我不知道怎么做?我知道我需要在加载和显示事件时执行类似 $(".fc-event.hidden").parent().remove() 的操作,但是 since v3 nothing like this exists UPDATE 即使它存在,当前 v5 删除 DOM 元素不会调整其他事件框的大小。
  3. 尝试修复库的代码 <-- 问题:如果下一版本的库没有解决方案,我不想担心补丁
  4. 加载时过滤事件 <-- 慢:我使用回调函数通过 Ajax 加载事件,我可以在那里进行快速过滤,但在这种情况下,我会失去性能,因为我每次我需要用 real_rc != 1
  5. 显示事件时,我都必须重新获取事件
  6. 自定义视图 <-- 我不想重新发明轮子。正如@saqibkafeel 在评论中所建议的那样 custom views 可用于创建新视图,但我喜欢当前视图并且并不真的需要新视图,只需按预期工作的默认视图即可。

有没有办法在不创建新问题的情况下绕过这个问题? (我觉得最简单的选择是找到一个钩子让我做选项号2,但是我花了一整天,我没有找到任何东西)。

正如您已经注意到的,CSS 和 JS 在这里无能为力,因为事件是使用 position:absolute 放置的,因此删除一个事件(甚至完全从 DOM 中删除)不会影响其他的显示。唯一的方法是在渲染之前从日历中删除事件。

所以删除事件而不是添加 class:

eventClassNames: function(arg) { /* you can also use "eventDidMount" */
       if (arg.view.type != 'resourceTimeGridDay') {
          if (arg.event.extendedProps.real_rc != "1") {
             arg.event.remove(); /* HERE */
          }
       }
    },

完整代码:

document.addEventListener('DOMContentLoaded', function() {
  var calendarEl = document.getElementById('calendar');

  var calendar = new FullCalendar.Calendar(calendarEl, {
    initialView: 'timeGridWeek',
    initialDate: '2020-12-22',
    headerToolbar: {
      left: 'prev,next today',
      center: 'title',
      right: 'dayGridMonth,timeGridWeek,timeGridDay'
    },
    height: 'auto',

    eventClassNames: function(arg) {
       if (arg.view.type != 'resourceTimeGridDay') {
          if (arg.event.extendedProps.real_rc != "1") {
             arg.event.remove();
          }
       }
    },

    events: [
      {
        title: 'Test Resource 1',
        real_rc: '1',
        start: '2020-12-22 13:00',
        end: '2020-12-22 14:00'
      },
      {
        title: 'Also resource 1',
        real_rc: '1',
        start: '2020-12-22 13:30',
        end: '2020-12-22 14:30'
      },
      {
        title: 'Resource 1',
        real_rc: '1',
        start: '2020-12-22 16:00',
        end: '2020-12-22 17:00'
      },
      {
        title: 'Resource 2',
        real_rc: '2',
        start: '2020-12-22 15:00',
        end: '2020-12-22 17:00'
      }
    ]
  });

  calendar.render();
});
html, body {
  margin: 0;
  padding: 0;
  font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
  font-size: 14px;
}

#calendar {
  max-width: 1100px;
  margin: 40px auto;
}
<link rel="stylesheet" href="https://unpkg.com/fullcalendar@5.1.0/main.min.css">
<script src="https://unpkg.com/fullcalendar@5.1.0/main.min.js"></script>
<div id='calendar'></div>

另一个想法是像下面这样控制事件的display

document.addEventListener('DOMContentLoaded', function() {
  var calendarEl = document.getElementById('calendar');

  var calendar = new FullCalendar.Calendar(calendarEl, {
    initialView: 'timeGridWeek',
    initialDate: '2020-12-22',
    headerToolbar: {
      left: 'prev,next today',
      center: 'title',
      right: 'dayGridMonth,timeGridWeek,timeGridDay'
    },
    height: 'auto',

    eventDidMount: function(arg) {
       if (arg.view.type != 'resourceTimeGridDay') {
          if (arg.event.extendedProps.real_rc != "1") {
             arg.event.setProp( 'display', 'none' );
          }
       }
    },

    events: [
      {
        title: 'Test Resource 1',
        real_rc: '1',
        start: '2020-12-22 13:00',
        end: '2020-12-22 14:00'
      },
      {
        title: 'Also resource 1',
        real_rc: '1',
        start: '2020-12-22 13:30',
        end: '2020-12-22 14:30'
      },
      {
        title: 'Resource 1',
        real_rc: '1',
        start: '2020-12-22 16:00',
        end: '2020-12-22 17:00'
      },
      {
        title: 'Resource 2',
        real_rc: '2',
        start: '2020-12-22 15:00',
        end: '2020-12-22 17:00'
      }
    ]
  });

  calendar.render();
});
html, body {
  margin: 0;
  padding: 0;
  font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
  font-size: 14px;
}

#calendar {
  max-width: 1100px;
  margin: 40px auto;
}
<link rel="stylesheet" href="https://unpkg.com/fullcalendar@5.1.0/main.min.css">
<script src="https://unpkg.com/fullcalendar@5.1.0/main.min.js"></script>
<div id='calendar'></div>


一个可以切换显示的交互式演示:

var rc = "1";

document.addEventListener('DOMContentLoaded', function() {
  var calendarEl = document.getElementById('calendar');

  var calendar = new FullCalendar.Calendar(calendarEl, {
    initialView: 'timeGridWeek',
    initialDate: '2020-12-22',
    headerToolbar: {
      left: 'prev,next today',
      center: 'title',
      right: 'dayGridMonth,timeGridWeek,timeGridDay'
    },
    height: 'auto',

    eventDidMount: function(arg) {
       if (arg.view.type != 'resourceTimeGridDay') {
          if (arg.event.extendedProps.real_rc != rc) {
             arg.event.setProp( 'display', 'none' );
          } 
       }
    },
    viewDidMount: function(arg) {
       var es = calendar.getEvents();
       for(var i=0;i<es.length;i++)
        es[i].setProp( 'display', 'auto' )
    },

    events: [
      {
        title: 'Test Resource 1',
        real_rc: '1',
        start: '2020-12-22 13:00',
        end: '2020-12-22 14:00'
      },
      {
        title: 'Also resource 1',
        real_rc: '1',
        start: '2020-12-22 13:30',
        end: '2020-12-22 14:30'
      },
      {
        title: 'Resource 1',
        real_rc: '1',
        start: '2020-12-22 16:00',
        end: '2020-12-22 17:00'
      },
      {
        title: 'Resource 2',
        real_rc: '2',
        start: '2020-12-22 15:00',
        end: '2020-12-22 17:00'
      }
    ]
  });

  calendar.render();
  document.querySelector("#toggle").addEventListener('click',function() {
    if (rc=="1") rc="2"; else rc = "1";
    /* trigger view change */
    calendar.changeView('dayGridMonth');
    calendar.changeView('timeGridWeek');
  });
});
html, body {
  margin: 0;
  padding: 0;
  font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
  font-size: 14px;
}

#calendar {
  max-width: 1100px;
  margin: 40px auto;
}
<link rel="stylesheet" href="https://unpkg.com/fullcalendar@5.1.0/main.min.css">
<script src="https://unpkg.com/fullcalendar@5.1.0/main.min.js"></script>
<button id="toggle">toggle</button>
<div id='calendar'></div>