【问题标题】:Rails, turbolinks and inline javascript. How to avoid duplicate event handlers?Rails、turbolinks 和内联 javascript。如何避免重复的事件处理程序?
【发布时间】:2016-09-27 00:56:42
【问题描述】:

我在网上看了很多帖子,但最后我还是没有找到一个很好的解决方案来处理 Turbolinks + 内联脚本。

Turbolinks 确实给人一种很好的感觉,我真的不想停止使用它,但在某些情况下,我很难调试重复的事件处理程序。

我对内联 javascript 有一些看法:我实际上更喜欢在与之交互的元素附近放置(小)javascript 代码,只为 app.js 保存大型 javascripts 函数。

想象一下,我有一个包含多个过滤器的搜索页面,但仅限于该特定页面。当用户更改搜索过滤器时,它应该获取(使用远程/AJAX)新结果。最简单的方法是引入

$(document).on('ready turbolinks:load', function() {
  // Submit on every change
  $('#myform input').change(function() {
    $('#myform').submit()
  }
})

当使用 turbolink 导航并返回搜索页面时,我自然会在每次选择时遇到多个重复绑定,从而导致多次提交表单。

我已经尝试添加

$('#sidebar-search input').unbind()

就在.change() 行之前,但它似乎不起作用,并且由于某种原因,该表单仍被多次发布:一次使用 AJAX,其他几个重复项(谢天谢地被取消)和另一个非远程请求(我的服务器用 HTML 回复)。

使用 turbolinks 5

【问题讨论】:

  • 您的 JS 有不平衡的花括号 - 它缺少 }。但既然你没有注意到语法错误,那可能只是一个糟糕的复制粘贴。

标签: javascript jquery ajax turbolinks ruby-on-rails-5


【解决方案1】:

据我所知,使用内联 JavaScript 时无法避免这个问题。 Turbolinks 自述文件“Working with Script Elements”部分建议在安装事件处理程序时避免内联<script>s:

Turbolinks 每次呈现页面时都会评估页面的 <body> 中的 <script> 元素。您可以使用内联正文脚本来设置每页 JavaScript 状态或引导客户端模型。要在页面更改时安装行为或执行更复杂的操作,请避免使用脚本元素并改用turbolinks:load 事件。

听起来您喜欢内联脚本的原因是相关的 JS 和 HTML 彼此相邻很方便。这是工作流程的问题。虽然恐怕我不知道有什么方法可以使单独的 JS 文件像内联 JS 一样方便,但您可以通过在 JS 曾经所在的 HTML 中添加注释来关闭它,说“这个模板有 JS只为它”。在编辑模板时,如果看到该注释,请在编辑器中以水平拆分方式打开相应的 JS 文件,这样您就可以同时查看这两个文件。如果您使用的是支持在文件中打开路径的编辑器,您甚至可以在注释中写下 JS 文件的路径,这样您就可以通过链接打开它。

您有多种选择来组织您的单页 JS sn-ps 进入哪些文件。您可以将它们放在每个控制器的 JS 文件中,例如 products.js,或全局文件 application.js,或者您可以创建一个新的全局文件single_page_js.js。然后您可以将 cmets 放在每个部分的上方,标记该代码影响的模板。或者,您也可以使用某种命名约定来将 JS 文件与模板匹配。例如,在为模板app/views/products/index.html.erb编写事件处理程序时,您可以将JS放在app/assets/javascripts/products_index.js中。

最适合您的是某种插件,它可以预处理您的 HTML 模板以删除 <script> 元素,将它们的内容复制到全局 JS 文件,并添加包装代码以确保该位 JS 只运行一次,首次访问该页面时。但是我不知道有这样的插件。

【讨论】:

    【解决方案2】:

    我曾经这样做过,除了针对特定链接禁用之外,从未遇到过 turbolink 的任何问题。

    function run_after_turbo(){
    
      $('#myform input').change(function() {
        $('#myform').submit()
      }
    
    }
    $(run_after_turbo);
    $(document).on("turbolinks:load", run_after_turbo);
    

    【讨论】:

      【解决方案3】:

      我遇到了类似的问题,并解决了切换到纯 js 的问题

      // 旧的

      $(document).on('click', 'a[data-toggle="submenu"]', function(event){                                                                              
        $(this).next('ul.submenu').slideToggle();                                                                                                     
          return false;                                                                                                                                 
      });  
      

      // 新的

      var subMenus = document.querySelectorAll('a[data-oggle="submenu"]');
        subMenus.forEach(function(subMenu){
          subMenu.addEventListener('click',function(event){
            $(subMenu).next('ul.submenu').slideToggle();
            event.preventDefault();
            event.stopPropagation();
        });
      });
      

      所以你的情况应该是这样的

         var form = doucument.querySelector('#myform input');
      form.addEventListener('change', function() {
          $('#myform').submit();
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-11-10
        • 1970-01-01
        • 2018-02-17
        • 2023-03-09
        • 1970-01-01
        • 2013-01-06
        • 2017-08-09
        相关资源
        最近更新 更多