You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Hotwire时如何高亮当前激活的导航链接?

Turbo环境下高亮当前菜单链接的解决方案

问题本质

你的代码失效是因为使用data: { turbo_frame: :main, turbo_action: 'replace' }后,Turbo仅替换页面的main区域,导航所在的头部没有被重新渲染,服务器端的current_page? helper无法重新执行,导致高亮状态无法更新。

可行解决方法

方法一:通过JavaScript监听Turbo事件动态更新高亮

利用Turbo提供的事件钩子,在页面/Frame更新后根据当前URL调整导航高亮状态,这是最贴合Turbo局部更新理念的方案。

  1. 修改导航HTML,给每个菜单项添加路径标识
<!-- navigation -->
<nav class="nav font-semibold text-md">
  <ul class="flex items-center">
    <li class="p-4 border-b-2 border-blue-600 border-opacity-0 hover:border-opacity-100 hover:text-blue-600 duration-200 cursor-pointer" data-path="<%= posts_path %>">
      <%= link_to 'Posts', posts_path, data: { turbo_frame: :main, turbo_action: 'replace' } %>
    </li>
    <li class="p-4 border-b-2 border-blue-600 border-opacity-0 hover:border-opacity-100 hover:text-blue-600 duration-200 cursor-pointer" data-path="<%= users_path %>">
      <%= link_to 'Users', users_path, data: { turbo_frame: :main, turbo_action: 'replace' } %>
    </li>
  </ul>
</nav>
  1. 添加JavaScript逻辑监听Turbo事件
// 监听Turbo页面加载完成事件
document.addEventListener('turbo:load', updateActiveNav);
// 监听main Frame加载完成事件
document.addEventListener('turbo:frame-load', function(event) {
  if (event.target.id === 'main') {
    updateActiveNav();
  }
});

function updateActiveNav() {
  const currentPath = window.location.pathname;
  // 移除所有菜单项的高亮类
  document.querySelectorAll('[data-path]').forEach(item => {
    item.classList.remove('border-opacity-100', 'text-blue-600');
  });
  // 给当前路径对应的菜单项添加高亮类
  const activeItem = document.querySelector(`[data-path="${currentPath}"]`);
  if (activeItem) {
    activeItem.classList.add('border-opacity-100', 'text-blue-600');
  }
}

方法二:用Stimulus控制器封装高亮逻辑(更优实践)

将高亮逻辑封装为Stimulus控制器,更符合Rails现代前端代码组织规范:

  1. 创建Stimulus控制器
// app/javascript/controllers/active_nav_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  connect() {
    this.updateActive()
    this.setupListeners()
  }

  setupListeners() {
    document.addEventListener('turbo:load', () => this.updateActive())
    document.addEventListener('turbo:frame-load', (e) => {
      if (e.target.id === 'main') this.updateActive()
    })
  }

  updateActive() {
    const currentPath = window.location.pathname
    this.element.querySelectorAll('[data-path]').forEach(item => {
      const isActive = item.dataset.path === currentPath
      item.classList.toggle('border-opacity-100', isActive)
      item.classList.toggle('text-blue-600', isActive)
    })
  }
}
  1. 在导航中引用控制器
<nav class="nav font-semibold text-md" data-controller="active-nav">
  <ul class="flex items-center">
    <li class="p-4 border-b-2 border-blue-600 border-opacity-0 hover:border-opacity-100 hover:text-blue-600 duration-200 cursor-pointer" data-path="<%= posts_path %>">
      <%= link_to 'Posts', posts_path, data: { turbo_frame: :main, turbo_action: 'replace' } %>
    </li>
    <li class="p-4 border-b-2 border-blue-600 border-opacity-0 hover:border-opacity-100 hover:text-blue-600 duration-200 cursor-pointer" data-path="<%= users_path %>">
      <%= link_to 'Users', users_path, data: { turbo_frame: :main, turbo_action: 'replace' } %>
    </li>
  </ul>
</nav>

不推荐的方案(供参考)

如果一定要用服务器端逻辑更新高亮,可以将导航放入独立的Turbo Frame,每次页面切换时同时更新导航Frame,但这会增加服务器请求量,性能不如前端方案高效。

内容的提问来源于stack exchange,提问作者Ahmed Gasanov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 09:05:33