如何维护 Drupal 中的超大型菜单
我曾经打开过一个包含数千个链接的 Drupal 菜单,然后眼看着浏览器比我先放弃。严格来说,页面是加载出来了。只是之后的每一次点击,都像是在要求一台老旧打印机解释自己的感受。
从 BigMenu 和 Menu Select 开始
如果一个 Drupal 网站有一个大型编辑菜单,首要问题通常不是架构,而是编辑器界面。当菜单增长到数千个链接时,核心的菜单管理页面可能会变得非常痛苦。BigMenu 通过改变编辑人员浏览和管理菜单的方式来处理这个问题:它不会强行把整棵树加载到页面上,而是在编辑人员需要时,通过 AJAX 打开子树。 https://www.drupal.org/project/bigmenu
这听起来像是小事,直到你在一个大型网站上使用过默认的菜单 UI。即使树是折叠的,如果 Drupal 必须先构建完整的树,页面才能变得可用,那仍然会很痛苦。BigMenu 的价值在于,它避免了这种早期的大规模加载。编辑人员看到的是他们请求的那一部分树,而不是整片森林。 https://www.drupal.org/project/bigmenu
Menu Select 解决的是另一种烦恼。在内容表单中,编辑人员经常需要选择一个父级菜单项。面对一个大型菜单,普通的选择列表是荒谬的。没人愿意为了把一个页面放到正确的父级下面,就在数千个项目中滚动查找。Menu Select 用一种更易用的层级结构替代了这种体验,并且可以添加自动补全功能,让编辑人员搜索父级链接,而不是手动在整个菜单中寻找。 https://www.drupal.org/project/menu_select
我喜欢这种分工。BigMenu 在你管理菜单本身时提供帮助。Menu Select 在你把内容附加到菜单时提供帮助。它们很容易被混淆,因为两者都涉及菜单 UX,但它们修复的是编辑工作流中的不同环节。
Menu Select Ajax:在编辑人员需要时再加载选项
带自动补全的 Menu Select 已经是很大一步改进。但在非常大的站点上,即使是更好的小部件,如果表单在编辑人员做任何操作之前就尝试准备过多菜单数据,仍然可能过于沉重。这就是基于 AJAX 的菜单选择模式有意义的地方。
思路很简单:表单不应该在初始加载时为一个巨大的菜单构建完整的父级选择器。它应该等待。当编辑人员选择一个菜单、输入搜索词或打开一个分支时,Drupal 可以发起一个小型 AJAX 请求,并只返回菜单中匹配的部分。Drupal 的 Form API 通过支持 AJAX 的表单元素来支持这种模式:用户操作会触发服务器端重建,并且只替换表单中被选定的部分。 https://www.drupal.org/docs/develop/drupal-apis/javascript-api/ajax-forms
实际上,一个 AJAX 菜单选择通常有两层。第一层是可见的选择器:搜索字段、父级选择器,或者一个小型可展开分支。第二层是存储的值:Drupal 在保存表单时真正需要的菜单链接插件 ID,或者父级引用。
这个区别很重要。编辑人员应该处理标签、路径和熟悉的页面标题。Drupal 应该存储稳定的机器值。当这两个关注点混在一起时,大型菜单小部件就会变得脆弱。你会看到重复标签、不清楚的父级选项,以及缓慢的表单重建。
一个好的 AJAX 菜单选择流程几乎会显得有些无聊。编辑人员开始输入标题的一部分。Drupal 返回一个简短的可能父级链接列表,最好带有足够的上下文,以便区分相同的标题。编辑人员选择其中一个。表单在后台存储所选的菜单链接。没有巨大的选择列表。没有完整树渲染。没有浏览器崩溃。
同样的模式也适用于可展开分支。先显示顶层。当编辑人员打开一个父级时,获取该父级的子项。如果他们再打开一个子项,就获取下一层。当数据集很大时,UI 就应该这样运行:小请求,小响应,清晰的下一步操作。
到了 10,000 个菜单项,就停止向前加载
一旦一个菜单达到大约 10,000 个项目,我就不再把它看作普通的 Drupal 菜单。技术上,它仍然是一个菜单。运营上,它更像是一个树形内容索引。
常见错误是从根开始,加载整棵树,展开活动路径,然后把大部分结果丢掉。这在小菜单上可行。对于一个巨大菜单来说,这是反过来了。
我使用过的更好方法是反向加载。从当前页面的活动菜单链接开始。从那里只加载它的父级。这样你就能获得活动路径,而不需要让 Drupal 构建所有无关的分支。Drupal 的菜单 API 支持这种移动方向:菜单链接管理器可以按路由查找链接,并且也会公开菜单链接插件的父级 ID。 https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Menu%21MenuActiveTrail.php/11.x https://api.drupal.org/api/drupal/core%21lib%21drupal%21core%21menu%21menulinkmanagerinterface.php/function/menulinkmanagerinterface%3A%3Agetparentids/9
这会完全改变成本结构。一个巨大菜单可能有 10,000 个项目,但一个页面的活动路径通常很短。也许五层。也许七层。即使是很深的目录,也很少会让一个项目拥有几十个祖先。因此,与其加载 10,000 个链接来发现一条路径,不如加载活动项并向上回溯。
之后,你可以决定页面真正需要多少周边导航。有时父级路径就够了。有时你还需要活动项的子项。有时你需要某一层级的兄弟项来构建栏目菜单。可以。那就有意地加载这些切片。不要让“我们需要导航”悄悄变成“每次请求都加载整棵树”。
Drupal 的菜单树系统本来就以树参数、活动路径和转换为基础来思考。常规的树加载方法可以沿当前活动路径展开链接,这在普通菜单中很有用。 https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Menu%21MenuLinkTreeInterface.php/interface/MenuLinkTreeInterface/8.2.x 不过,对于非常大的菜单,我更愿意严格一些。先找到活动链接。然后加载它的父级。然后只加载当前页面所需的分支。
真正的维护规则:永远不要让编辑人员为整个菜单买单
巨大的 Drupal 菜单不只是渲染问题。它们是编辑问题、表单构建问题、缓存问题,有时也是某人拖延了三年的信息架构问题。
BigMenu 帮助编辑人员处理大型树结构,而不必一次性打开所有内容。 https://www.drupal.org/project/bigmenu Menu Select 让父级选择变得可以忍受,尤其是在配合自动补全时。 https://www.drupal.org/project/menu_select AJAX 选择可以防止表单在编辑人员做出第一个有意义的点击之前,就准备成千上万个选项。 https://www.drupal.org/docs/develop/drupal-apis/javascript-api/ajax-forms
对于前端导航,反向加载是我最会强力保护的部分。从活动菜单链接开始。只加载父级。只有当设计确实需要时,才添加子项或兄弟项。仅仅这个习惯,就能防止一个 10,000 项菜单把每次请求都变成惩罚。
浏览器永远不应该仅仅因为一个页面需要知道自己位于哪里,就必须背负整个菜单。
正在寻找市场上最好的 Drupal 开发公司?你已经找到了。
我们是最大的专注于 Drupal 的数字 agency,旨在交付快速、安全、可扩展的平台,毫不妥协。从新建项目和重新设计,到迁移和长期支持,我们的 Drupal 专家都能交付企业级成果,并提供精品团队级别的关注。
今天就预约一次通话,让我们把你的 Drupal 路线图变成高性能的现实。