【问题标题】:Why would this JS fire on a form partial rendered on 1 page but not another?为什么这个 JS 会在部分呈现在 1 页而不是另一页的表单上触发?
【发布时间】:2015-02-20 00:34:21
【问题描述】:

我有一个如下所示的posts.js 文件:

var ready;
ready = function() {

    var toggleSidebar = $(".togglesidebar");
    var primary = $("#primary");
    var secondary = $("#secondary");

    toggleSidebar.on("click", function(){

        if(primary.hasClass("col-sm-9")){
            primary.removeClass("col-sm-9");
            primary.addClass("col-sm-12");
            secondary.css('display', 'none');
        }
        else {
            primary.removeClass("col-sm-12");
            primary.addClass("col-sm-9");
            secondary.css('display', 'inline-block');
        }
    }); 
};

var counter = function(event) {
    var fieldValue = $(this).val();
    var wc = fieldValue.trim().replace(regex, ' ').split(' ').length;
    var regex = /\s+/gi;
    var $wcField;
    var maxWc;

    if ($(this)[0] === $('#post_title')[0]) {
      $wcField = $('#wordCountTitle');
      maxWc = 7;
    } else {
      $wcField = $('#wordCountBody');
      maxWc = 150;
    }

    $wcField.html(wc);
    $wcField.toggleClass('over-limit', wc > maxWc);
};

$(document).ready(ready);
$(document).on('ready page:load', function () {
    $('#post_title, #body-field').on('change keyup paste', counter);
});

在我的application.html.erb 页面中,我有这个:

<div id="secondary" class="col-sm-3 sidebar" style="display: none;">
    <aside>
      <div class="about">
        <h4>Submit Report</h4>
            <%= render "posts/form" %>
        </div>
    </aside> 
</div>  <!-- /#secondary --> 

当我切换这个 div 并显示 _form 部分时,JS 在这些字段中工作正常。

但如果我去posts/new/posts/:id/edit,它不会。

即使我检查该页面的来源,我也会看到其中包含post.js

这可能是什么原因造成的?

编辑 1

我正在使用 Turbolinks,如果这很重要的话。

编辑 2

根据答案中的建议,我尝试了这个:

var ready;
ready = function() {

    // This is the Sidebar toggle functionality
    var toggleSidebar = $(".togglesidebar");
    var primary = $("#primary");
    var secondary = $("#secondary");

    $(document).on("click", ".togglesidebar", function(){       

        if(primary.hasClass("col-sm-9")){
            primary.removeClass("col-sm-9");
            primary.addClass("col-sm-12");
            secondary.css('display', 'none');
        }
        else {
            primary.removeClass("col-sm-12");
            primary.addClass("col-sm-9");
            secondary.css('display', 'inline-block');
        }
    }); 
};

但这并没有奏效。

我遇到的关键问题是“计数器”,即#wordCountTitle#wordCountBody 在我的/posts/new 上不起作用,即使它们在posts/index 被激活时在posts/index 上起作用.

【问题讨论】:

  • 您是否将该文件包含在 app/assets/javascripts 下的 application.js 文件中?听起来像是资产管道问题。
  • 我的application.js 中有//= require_tree .。那应该涵盖我的 JS 目录中的所有内容吗?
  • 你在使用turbolinks吗?
  • @John 是的。我确定。
  • Turbolinks 会导致在页面之间加载 JavaScript 时出现问题。 JavaScript 的哪一部分没有被触发?尝试在$(document).ready(ready); 之后添加$(document).on('page:load', ready);

标签: javascript jquery ruby-on-rails ruby-on-rails-4 asset-pipeline


【解决方案1】:

您可以在文档上使用事件处理程序,而不是直接绑定到需要仔细处理 Turbolinks 事件的元素的 onclick,尝试更改直接事件

toggleSidebar.on("click", function(){

到委托的事件

$(document).on("click", ".togglesidebar", function(){

当您动态修改 DOM(如 Turbolinks 替换它时)如果您使用直接事件,那么您需要重新分配它。

详细解释见http://api.jquery.com/on/#direct-and-delegated-events


第一个函数代表第二个函数。此外,对于委托事件,“就绪”检查变得不必要。考虑到这一点,您的代码将变为:

$(document).on("click", ".togglesidebar", function(){

    var primary = $("#primary");
    var secondary = $("#secondary");

    if(primary.hasClass("col-sm-9")){
        primary.removeClass("col-sm-9");
        primary.addClass("col-sm-12");
        secondary.css('display', 'none');
    }
    else {
        primary.removeClass("col-sm-12");
        primary.addClass("col-sm-9");
        secondary.css('display', 'inline-block');
    }

}); 

$(document).on('change keyup paste', '#post_title, #body-field', function () {
    var fieldValue = $(this).val();
    var wc = fieldValue.trim().replace(regex, ' ').split(' ').length;
    var regex = /\s+/gi;
    var $wcField;
    var maxWc;

    if ($(this)[0] === $('#post_title')[0]) {
      $wcField = $('#wordCountTitle');
      maxWc = 7;
    } else {
      $wcField = $('#wordCountBody');
      maxWc = 150;
    }

    $wcField.html(wc);
    $wcField.toggleClass('over-limit', wc > maxWc);
});

【讨论】:

  • 我试过这个,但它不起作用。为了清楚起见,我在ready() 函数中将这行:`toggleSidebar.on("click", function(){` 替换为这行:$(document).on("click", ".togglesidebar", function(){。此外,问题主要出在单词和字符计数器上。这就是我的/posts/new/ 页面上不起作用的原因。此更改无法解决此问题。
  • 由于某种原因,即使使用您的新代码,计数器仍然无法在该页面上工作。但它适用于原始部分。
【解决方案2】:

我在我的一个项目中使用了类似的东西,遇到了同样的问题希望它有所帮助:

window.onLoad = function(callback) {
  $(document).ready(callback);
  $(document).on('page:load', callback);
};

然后用 onLoad 封装我的函数,类似于

onLoad(function() {
  counter()
});

onLoad函数绑定ready事件和turbolink page:load事件

【讨论】:

  • 我试过这个,但它似乎对我不起作用。或者更确切地说,我的实现似乎不起作用。
【解决方案3】:

当你这样做时

$("selector").on("click", function(){});

您实际上将选择器绑定到点击事件。

如果你使用白色

$(document).on("click", "selector", function(){});

您将单击事件绑定到文档,单击后会检查单击的元素是否是您使用的选择器。如果是,则执行该功能。因此,在动态元素上绑定事件时,您应该使用第二种方法。

我希望能回答“为什么”的问题

【讨论】:

  • 我尝试对此进行调整,请参阅我对 agios 答案的评论,但没有成功。有什么想法吗?
【解决方案4】:

我很长时间不使用 jQuery,但自从我来到这里:如果你有多个带有选择器“.sidebar”的元素,我相信你需要使用“.each”来绑定函数到 dom 上与该选择器匹配的所有元素。

参考这里http://api.jquery.com/each/

希望这会有所帮助,祝你好运。

【讨论】:

    【解决方案5】:

    我查看了 Turbolinks,它做了我认为它做的事情:它将链接的 HTML 内容加载到主页上的容器内。问题是,它加载的任何内容都与您在主页加载时声明的任何事件和函数无关,因此确实,在第一次点击之后,它刚刚加载的 HTML 上的选择器不会将点击事件归因于它(绑定时它不在 DOM 上)。

    可能的解决方案:我对 .live() 方法做了一些研究,但它已被弃用,所以我建议这样做:

    $('body').on('click','a.saveButton', saveHandler)

    绑定更接近您需要的元素似乎将确保在主体内加载的任何 Turbolinks 都将获得您声明的绑定。

    这里有更详细的答案:Javascript event binding persistence

    .live 钩子的文档在这里:http://api.jquery.com/live/#typefn

    我过去曾经在我的网页上使用相同的架构,但我确实遇到了与您类似的问题。

    希望对你有帮助。

    【讨论】:

      【解决方案6】:

      它应该有效吗.. 确保:

      1. 没有 id 冲突。
      2. 您的 html 结构,可能您忘记在帖子中设置值了。
      3. 可能是posts.js路径错误,用CTRL+U打开,然后点击post.js,显示你的代码,如果有那么没关系。

      我这样试试,没关系(dummy):

      $(document).on("click", ".togglesidebar", function(){
      
          var primary = $("#primary");
          var secondary = $("#secondary");
      
          if(primary.hasClass("col-sm-9")){
              primary.removeClass("col-sm-9");
              primary.addClass("col-sm-12");
              secondary.css('display', 'none');
          }
          else {
              primary.removeClass("col-sm-12");
              primary.addClass("col-sm-9");
              secondary.css('display', 'inline-block');
          }
      	
      	
      
      }); 
      
      $(document).on('change keyup paste', '#post_title, #body-field', function () {
          
          var fieldValue = $(this).val();
          var wc = fieldValue.trim().replace(regex, ' ').split(' ').length;
      	
      	console.log(wc);
      	
          var regex = /\s+/gi;
          var $wcField;
          var maxWc;
      
          if ($(this)[0] === $('#post_title')[0]) {
            $wcField = $('#wordCountTitle');
            maxWc = 7;
          } else {
            $wcField = $('#wordCountBody');
            maxWc = 150;
          }
      
          $wcField.html(wc);
          $wcField.toggleClass('over-limit', wc > maxWc);
      });
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      <div class="togglesidebar">Toogle</div>
      <div id="wordCountTitle"></div>
      <div id="wordCountBody"></div>
      <div id="primary">
      <div id="secondary" class="col-sm-3 sidebar" style="display: none;">
          <aside>
            <div class="about">
              <h4>Submit Report</h4>
                  <input type="text" id="body-field"/>
              </div>
          </aside> 
      </div>  <!-- /#secondary --> 
      </div>

      【讨论】:

        【解决方案7】:

        老实说,对于涉及 Turbolinks 的 Js 问题,让它有效工作的最佳方法是安装 jquery rails gem,添加 //require jquery-Turbolinks 然后在你的 Js 文件中删除 //require turbolinks

        【讨论】:

          【解决方案8】:

          确保您在 jQuery 选择器上传递的 id 是唯一的。如果该页面/部分在没有回发的情况下加载,您应该使用

          //document or selector that does not get removed
          var primary = $(document).find('#primary'); 
          var secondary = $(document).find('#secondary');
          

          这个,和

          $(document).click('eventName', 'contextSelector', function)
          

          应该有助于解决问题。

          【讨论】:

            【解决方案9】:

            如果#post_title#body-field 是动态创建的,您需要进行更改:

            $('#post_title, #body-field').on('change keyup paste', counter);
            

            到这里:

            $(document).on('change keyup paste', '#post_title, #body-field', counter);
            

            当定位页面加载时不存在的元素(可能是 #post_title 和 @987654327 @)。

            【讨论】:

              【解决方案10】:

              关于/posts/new 上的$('#wordCountTitle')$('#wordCountBody'),您是否尝试过在控制台中输入其中任何一个? /posts/new 的视图可能与您的索引不同并且缺少这些 id(或者您将它们设置为类或发生了其他一些转置)。

              我在使用 Turbolinks 和 jquery 时遇到了各种各样的问题,所以关于如何解决您的问题的一些建议:

              1. 使用gem 'turbolinks' 包含它。按照说明使用 Ruby (gems) 方式而不是 PHP 方式。

              2. 使用 Turbolinks 意味着$(document).ready 在新“页面”加载时不会触发。解决方案是使用:$(document).on('page:load', ready)$(document).ready(ready)page:load 事件是 ready 事件的 Turbolinks 版本。

              3. 其他人提出了建议,但我发现它在我的 rails 应用程序中非常有价值:绑定到文档不是直接将事件绑定到选择器 $("a").click(/* function */),而是绑定到文档意味着当 Turbolinks 加载新页面时,文档绑定在页面加载后幸存:$(document).on('click', 'a.particularAnchor', particularAnchorClicked)

              考虑到你的具体代码,我会改变这个:

              $('#post_title, #body-field').on('change keyup paste', counter);
              

              $(document).on('change keyup paste', '#post_title, #body-field', counter);
              

              在我看来,在您的 counter 函数中,您将以下两行混合在一起(需要先定义 regex

              var wc = fieldValue.trim().replace(regex, ' ').split(' ').length;
              var regex = /\s+/gi;
              

              【讨论】:

                猜你喜欢
                • 2021-12-09
                • 1970-01-01
                • 2020-07-28
                • 2015-11-27
                • 1970-01-01
                • 2019-07-06
                • 2018-07-11
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多