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

Rails5/jQuery中click touchstart事件仅首次加载有效问题求助

问题:Turbolinks导致Bourbon/Refills滑动面板点击事件失效

我在用Bourbon/Refills的sliding_panel组件做导航菜单,给相关元素绑定了on('click touchstart')事件,用toggleClass控制菜单显示隐藏。页面第一次加载时没问题,但后续切换页面后事件就失效了。我怀疑是Turbolinks的问题,装了jquery-turbolinks gem配置好还是没解决,有人遇到过类似情况吗?

我的代码如下:

模板代码 (_navbar.html.erb)

<button type="button" class="js-menu-trigger sliding-panel-button"> Click for Sliding Panel </button> 
<nav class="js-menu sliding-panel-content"> 
  <ul> 
    <li><%= link_to 'Users', users_path %></li> 
    <li><a href="javascript:void(0)">Item 2</a></li> 
    <li><a href="javascript:void(0)">Item 3</a></li> 
  </ul> 
</nav> 
<div class="js-menu-screen sliding-panel-fade-screen"></div>

JavaScript代码 (sliding_panel.js)

$(document).ready(function(){ 
  $('.sliding-panel-button,.sliding-panel-fade-screen,.sliding-panel-close').on('click touchstart',function (e) { 
    $('.sliding-panel-content,.sliding-panel-fade-screen').toggleClass('is-visible'); 
    e.preventDefault(); 
  }); 
});

SCSS代码 (sliding_panel.scss)

.sliding-panel-content { 
  $action-color: #477DCA !default; 
  $dark-gray: #333 !default; 
  $sliding-panel-border-color: $dark-gray; 
  $sliding-panel-background: lighten($sliding-panel-border-color, 5%); 
  $sliding-panel-color: #fff; 
  $sliding-panel-border: 1px solid $sliding-panel-border-color; 
  $sliding-panel-background-hover: $action-color; 
  $sliding-panel-color-hover: #fff; 
  $sliding-panel-background-focus: lighten($sliding-panel-background, 5%); 

  @include position(fixed, 0 auto 0 0); 
  @include size(220px, 100%); 
  background: $sliding-panel-background; 
  -webkit-overflow-scrolling: touch; 
  overflow-y: auto; 
  transform: translateX(-220px); 
  transition: all 0.25s linear; 
  z-index: 999999; 

  ul { 
    padding: 0; 
    margin: 0; 
  } 

  li { 
    list-style: none; 
  } 

  li a { 
    border-bottom: $sliding-panel-border; 
    color: $sliding-panel-color; 
    display: block; 
    font-weight: bold; 
    padding: 1em; 
    text-decoration: none; 

    &:focus { 
      background-color: $sliding-panel-background-focus; 
    } 

    &:hover { 
      background-color: $sliding-panel-background-hover; 
      color: $sliding-panel-color-hover; 
    } 
  } 

  &.is-visible { 
    transform: translateX(0); 
  } 
} 

.sliding-panel-fade-screen { 
  @include position(fixed, 0); 
  background: black; 
  opacity: 0; 
  transition: all 0.2s ease-in-out; 
  visibility: hidden; 
  z-index: 999998; 

  &.is-visible { 
    opacity: 0.4; 
    visibility: visible; 
  } 
} 

.sliding-panel-button { 
  cursor: pointer; 
  display: inline-block; 
  outline: none; 
  padding: 10px 16px; 
  position: relative; 

  img { 
    height: 1.3em; 
  } 
}

解答

嘿,我之前也碰到过一模一样的问题!Turbolinks的坑就在这儿——它会替换页面的内容,但不会重新执行$(document).ready()里的代码,所以新加载的页面里的元素根本没绑定上事件。jquery-turbolinks有时候能解决,但不是所有情况都管用,尤其是当代码结构没适配Turbolinks的时候。给你两个靠谱的解决办法:

方法一:用Turbolinks的turbo:load事件替代$(document).ready()

Turbolinks会在页面加载完成(包括首次加载和Turbolinks跳转后的加载)时触发turbo:load事件(如果是Turbolinks 5之前的版本是turbolinks:load,注意区分版本)。把你的代码改成这样:

$(document).on('turbo:load', function(){ 
  // 先解绑再绑定,避免重复绑定导致多次触发
  $('.sliding-panel-button,.sliding-panel-fade-screen,.sliding-panel-close')
    .off('click touchstart')
    .on('click touchstart',function (e) { 
      $('.sliding-panel-content,.sliding-panel-fade-screen').toggleClass('is-visible'); 
      e.preventDefault(); 
    }); 
});

方法二:用事件委托(Event Delegation)

另一个更稳妥的办法是把事件绑定在document这类一直存在的元素上,不管元素是一开始就存在还是后来动态加载的,事件都能通过冒泡触发:

$(document).on('click touchstart', '.sliding-panel-button,.sliding-panel-fade-screen,.sliding-panel-close', function (e) { 
  $('.sliding-panel-content,.sliding-panel-fade-screen').toggleClass('is-visible'); 
  e.preventDefault(); 
});

这种方式不需要依赖Turbolinks的特定事件,兼容性更好,就算以后Turbolinks版本更新也不容易出问题,我个人更推荐这个方法!

你可以先试试方法二,应该能直接解决问题!


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:21:28