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

Rails项目中JavaScript仅直接URL生效,菜单跳转失效问题求助

问题原因

你遇到的问题是因为Turbo Rails的特性导致的:当通过菜单链接跳转时,Turbo Drive会执行局部页面刷新(只替换页面内容而非重新加载整个文档),而你的JavaScript代码绑定在DOMContentLoaded事件上——这个事件仅在首次加载完整文档时触发,Turbo跳转时不会再次触发,所以脚本无法执行。

解决方案

以下是几种可行的解决方式,按推荐程度排序:

方式1:改用Turbo生命周期事件替换DOMContentLoaded

将脚本中的DOMContentLoaded监听替换为Turbo提供的turbo:load或turbo:render事件,这两个事件会在首次加载和Turbo导航完成后都触发。同时建议添加元素存在判断和事件重复绑定的处理:

document.addEventListener('turbo:load', function() {
    var optionSelect = document.getElementById('option-select');
    var dateInput1 = document.getElementById('date-input1');
    var dateInput2 = document.getElementById('date-input2');

    // 避免元素不存在时报错
    if (!optionSelect || !dateInput1 || !dateInput2) return;

    // 先移除旧的事件监听,防止重复绑定
    function handleOptionChange() {
        if (optionSelect.value === '1') {
            dateInput1.removeAttribute('readonly');
            dateInput2.removeAttribute('readonly');
            dateInput1.style.backgroundColor = '';
            dateInput2.style.backgroundColor = '';
        } else {
            dateInput1.setAttribute('readonly', true);
            dateInput2.setAttribute('readonly', true);
            dateInput1.style.backgroundColor = '#fbfbfe';
            dateInput2.style.backgroundColor = '#fbfbfe';
        }
    }
    optionSelect.removeEventListener('change', handleOptionChange);
    optionSelect.addEventListener('change', handleOptionChange);

    // 初始化输入框状态
    if (optionSelect.value === '') {
        dateInput1.setAttribute('readonly', true);
        dateInput2.setAttribute('readonly', true);
        dateInput1.style.backgroundColor = '#fbfbfe';
        dateInput2.style.backgroundColor = '#fbfbfe';
    }
});

方式2:使用Stimulus控制器(推荐,符合Rails现代前端实践)

Stimulus是Rails官方推荐的轻量级前端控制器,会自动在元素挂载到DOM时执行初始化逻辑,Turbo跳转时也会自动清理旧元素的控制器,避免重复绑定问题。

步骤1:创建Stimulus控制器

在app/javascript/controllers/date_field_controller.js中添加:

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  // 定义目标元素,对应视图中的data-target属性
  static targets = ["optionSelect", "dateInput1", "dateInput2"]

  // 元素挂载到DOM时自动执行
  connect() {
    this.updateDateInputs()
    this.optionSelectTarget.addEventListener('change', () => this.updateDateInputs())
  }

  // 封装输入框状态更新逻辑
  updateDateInputs() {
    const isEditable = this.optionSelectTarget.value === '1'
    const readonly = !isEditable
    const bgColor = readonly ? '#fbfbfe' : ''

    this.dateInput1Target.readOnly = readonly
    this.dateInput1Target.style.backgroundColor = bgColor
    this.dateInput2Target.readOnly = readonly
    this.dateInput2Target.style.backgroundColor = bgColor
  }
}

步骤2:在视图中绑定控制器

修改你的.html.erb视图,给元素添加Stimulus相关属性:

<select id="option-select" data-controller="date-field" data-date-field-option-select-target>
  <!-- 你的选项内容 -->
</select>

<input id="date-input1" type="date" data-date-field-date-input1-target>
<input id="date-input2" type="date" data-date-field-date-input2-target>

这样无论刷新页面还是Turbo跳转,Stimulus都会自动初始化输入框的状态和事件监听。

方式3:禁用特定链接的Turbo(不推荐,仅临时应急)

如果只想快速解决单个链接的问题,可以给菜单链接添加data-turbo="false"属性,强制跳转时重新加载整个页面:

<li><a class="dropdown-item" href="<%= new_admin_system_path %>" data-turbo="false">Add system</a></li>

但这种方式会失去Turbo带来的性能优化,不推荐作为长期解决方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 02:34:59