Rails 7应用中返回按钮/菜单项点击时JavaScript无法运行求助
解决Rails 7 Turbo下个人资料页面JS仅全页刷新运行的问题
Rails 7默认使用Hotwire Turbo(原Turbolinks的升级版本),通过Turbo导航加载页面时,不会触发window.load这类完整页面刷新的事件,这就是你的JS仅在全页刷新时生效的核心原因。以下是针对性的解决方案:
核心修改思路
- 改用Turbo专属事件触发初始化逻辑
- 使用事件委托绑定交互事件,避免重复绑定且适配Turbo的页面替换机制
- 修复原代码中的语法错误
修改后的profile.js代码
// 监听Turbo页面渲染完成事件(Turbo导航或首次加载都会触发) document.addEventListener('turbo:render', updateProfile); // 兼容首次全页加载的场景 document.addEventListener('DOMContentLoaded', updateProfile); function fileSelected() { const file = document.querySelector('#fileInput').files[0]; if (!file) return; const reader = new FileReader(); reader.onload = function(event) { document.querySelector('#profile-image').src = event.target.result; }; reader.readAsDataURL(file); } function updateProfile() { // 用事件委托绑定输入验证事件(避免重复绑定) document.addEventListener('input', function(event) { if (event.target.id !== 'name') return; const errorElement = document.getElementById('error-message-name'); const regex = /^.{3,}$/; const value = event.target.value; if (regex.test(value)) { errorElement.classList.remove("visible-error"); errorElement.classList.add("invisible-error"); } else { errorElement.classList.remove("invisible-error"); errorElement.classList.add('visible-error'); } }, { capture: true }); // 用事件委托绑定切换按钮事件 document.addEventListener('click', function(event) { if (event.target.id !== 'toggle') return; const toggleSwitch = event.target; if (toggleSwitch.getAttribute('data-type') === "influencer") { toggleSwitch.setAttribute('data-type', "vender"); document.getElementById('profile_type').value = "vender"; } else { toggleSwitch.setAttribute('data-type', "influencer"); document.getElementById('profile_type').value = "influencer"; } }, { capture: true }); // 用事件委托绑定保存按钮事件 document.addEventListener('click', function(event) { if (event.target.id !== 'save-button') return; const newName = document.getElementById('name').value; const newHeadline = document.getElementById('headline').value; const newCountry = document.getElementById('country').value; const newCity = document.getElementById('city').value; const newAbout = document.getElementById("about").value; const newProfileType = document.getElementById('toggle').getAttribute('data-type'); const userId = document.getElementById('user_id').getAttribute('data'); const fileInput = document.getElementById("fileInput"); const file = fileInput.files[0]; if (!file) { $.ajax({ type: "PATCH", url: encodeURI(`/users/${userId}`), beforeSend: function(xhr) { xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content')); }, data: { user: { profile_type: newProfileType, name: newName, headline: newHeadline, country: newCountry, city: newCity, about: newAbout } }, success: function() { console.log("Update success.") } }); } else { const formData = new FormData(); formData.append("avatar", file); $.ajax({ url: encodeURI(`/users/${userId}`), type: "PUT", beforeSend(xhr, options) { xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content')); xhr.setRequestHeader('image-change', true); options.data = formData; }, success: function() { console.log("Image Update success.") }, error: () => { alert("An issue occured. Please try again."); } }); } }, { capture: true }); }
关键说明
- Turbo事件替换:用
turbo:render替代window.load,该事件在Turbo完成页面内容替换后触发,无论是首次加载还是Turbo导航都会执行初始化逻辑。 - 事件委托优势:将事件绑定到
document而非单个元素,既避免了每次页面渲染重复绑定事件的问题,又能确保Turbo新渲染的元素能正常响应交互。 - 修复语法错误:原代码中
regex.test(value)的value未定义,已改为event.target.value,确保验证逻辑正常运行。 - 无需强制刷新:移除了原代码中
window.location.reload()的逻辑,保留Turbo的无刷新导航体验。
你的html.erb代码无需改动,data: { "turbolinks-track": "reload" }属性已经能正确跟踪JS文件的缓存更新。
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

