为什么这个 JS 会在 1 页上部分呈现的表单上触发,而不是在另一个页面上触发

Why would this JS fire on a form partial rendered on 1 page but not another?

本文关键字:另一个 表单 会在 JS 为什么      更新时间:2024-01-25

我有一个看起来像这样的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

我正在使用涡轮链接,如果这很重要的话。

编辑 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,即使它们在激活.toggleSidebar时在posts/index上工作。

与其直接绑定到需要仔细处理 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);
});

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

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

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

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

onLoad 函数绑定就绪事件和涡轮链接页面:加载事件

当你这样做时

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

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

白色(如果使用(

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

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

我希望这回答了"为什么"的问题

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

有关参考,请转到此处 http://api.jquery.com/each/

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

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

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

$('

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

绑定到

你需要的元素,似乎可以确保Turbolinks在体内加载的任何内容都会得到你声明的绑定。

这里有一个更详细的答案:Javascript事件绑定持久性

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

过去,

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

希望对您有所帮助。

如果它有效.. 确保:

  1. 没有 id 冲突。
  2. 你的html结构,也许你忘记在你的帖子中放值。
  3. 也许错误的路径帖子.js,使用 CTRL+U 打开,然后单击发布.js显示您的代码的内容,如果有的话,没关系。

我试试这样,没关系(假人(:

$(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>

老实说,对于涉及 Turbolinks 的 Js 问题,让它

高效工作的最佳方法是安装 jquery rails gem,添加//require jquery-Turbolinks,然后在 Js 文件中删除//require turbolinks

确保在 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)

应该有助于解决问题。

如果#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#body-field(时,您需要将事件委托给页面加载时存在的元素(在本例中为document本身(。

关于/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;