「实战应用」如何用DHTMLX将上下文菜单集成到JavaScript甘特图中(一)

发布时间:2026/7/14 13:39:13
「实战应用」如何用DHTMLX将上下文菜单集成到JavaScript甘特图中(一) DHTMLX Gantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表。可满足项目管理应用程序的所有需求是最完善的甘特图图表库。DHTMLX Gantt是一个高度可定制的工具可以与项目管理应用程序所需的其他功能相补充。在本文中您将学习如何使用自定义上下文菜单来补充基于DHTMLX的JavaScript甘特图来提高用户在任务管理中的效率。考虑到DHTMLX产品的良好互兼容性DHTMLX Suite的Menu小部件是实现本教程目标的甘特图组件的完美补充。让我们更详细地介绍一下这个演示并为您提供技术细节将类似的功能集成到项目中。初始化和配置上下文菜单在用例场景中上下文菜单是一个有用的UI元素它可以根据用户与甘特图交互的上下文显示不同的选项。如果您右键单击下面示例中甘特图的任何任务可以尝试所有可用的任务操作。为了节省时间我们将省略明确描述甘特图组件的初始化阶段直接使用DHTMLX Menu实现上下文菜单。第一步是创建上下文菜单的新实例。let contextMenu new dhx.ContextMenu(null, { css: dhx_widget--bg_gray });之后使用onContextMenu事件处理程序该处理程序在右键单击任务后触发。gantt.attachEvent(onContextMenu, function (taskId, linkId, event) {在菜单配置中根据单击位置显示不同的菜单项。在时间轴中调用常规任务的上下文菜单时它将包含“拆分任务”项。但是在项目类型任务的上下文菜单中以及在网格区域调用任务菜单时此选项不可用因为假设任务应该在单击位置进行拆分。在事件处理程序中函数的最开始有必要收集上下文菜单调用的确切位置的信息。let itemsConfig null; if (taskId) { const task gantt.getTask(taskId);为此您需要几个配置(变量)isTaskBar– 显示时间轴中的任务栏(此处不考虑任务类型)是否被单击。const isTaskBar event.target.closest(.gantt_task_line);isParentTask– 显示任务是否有子任务。const isParentTask gantt.hasChild(task.id);isSplitTask– 当任务的所有子任务(任务栏)显示在时间轴的单行上时显示任务是否以拆分模式呈现。const isSplitTask task.render split;barHidden– 显示任务是否显示在时间轴中。const barHidden task.hide_bar;如果任务有父任务则需要确定其父任务是否显示在分裂模式中。它是这样做的let hasSplitParent false; if (task.parent) { const parent gantt.getTask(task.parent); hasSplitParent parent.render split; }之后您需要将所有参数添加到itemsConfig对象。itemsConfig { isTaskBar, isParentTask, isSplitTask, barHidden, hasSplitParent };对于自定义上下文菜单您需要删除所有以前的上下文菜单项然后添加由generateMenuItems函数返回的新项。contextMenu.data.removeAll(); contextMenu.data.parse(generateMenuItems(itemsConfig));现在是时候在单击位置显示上下文菜单了。contextMenu.showAt(event);接下来您需要计算鼠标点击相对于时间轴的位置。从得到的单击位置您将获得单击日期它应该被添加到clickDate参数中它将用于各种上下文菜单操作。const clickPosition gantt.utils.dom.getRelativeEventPosition(event, gantt.$task_data).x; clickDate gantt.dateFromPos(clickPosition)onContextMenu事件处理程序的函数必须返回false以禁用默认的上下文菜单功能(即浏览器不应该显示默认的上下文菜单)。现在让我们返回到generateMenuItems函数在这个函数中生成上下文菜单项的数据。上下文菜单项的每个对象都包含一个图标、项类型、ID和文本。{ icon: dxi dxi-chevron-up, type: menuItem, id: add_sibling_above, value: Add sibling above, },接下来您需要为“取消复制/剪切操作”和“显示所有隐藏任务”两个菜单项创建对象。const cancelCopyCut { icon: dxi dxi-close, type: menuItem, id: cancel_paste, value: Cancel copy/cut operation, }; const showAllHidden { icon: dxi dxi-eye, type: menuItem, id: show_hidden, value: Show all hidden tasks, };在网格或时间轴上单击任务栏后将使用配置调用该函数并将各种元素添加到上下文菜单中。当在甘特图的其他区域发生单击时需要检查是否选择了用于复制和剪切的任务。如果是则将此对象添加到菜单项数组中。如果隐藏了某些任务则会添加第二个菜单项。在上述条件下无论单击甘特图中的位置如何这些菜单项将始终可见。const menuItems []; if (tasksToCopy.length tasksToCut.length 1) { menuItems.push(cancelCopyCut); } if (Object.keys(hiddenTasks).length) { menuItems.push(showAllHidden); } return menuItems;现在回到上下文菜单配置在创建上下文菜单的实例之前考虑使用generateMenuItems函数是合理的以免以后再回到这个问题上。您必须为单击上下文菜单项添加事件处理程序。对于每次单击将调用单击函数这个函数将使用菜单项的ID。contextMenu.events.on(click, function (id, e) { applyCommand(id); targetId null; });现在我们可以分别关注每个上下文菜单选项的配置。篇幅有限未完待续更多内容敬请期待.......