【问题标题】:Why does this jQuery .change event stop working after .click event为什么这个 jQuery .change 事件在 .click 事件之后停止工作
【发布时间】:2015-06-02 15:50:56
【问题描述】:

我有一个脚本,它显示来自数组的问题,并使用两个按钮上的.click 事件从一个问题切换到下一个问题:上一个和下一个。当我加载页面时,$(":radio").change 选择器工作正常,但是当我单击上一个或下一个时它停止工作。

我尝试将$("#previous) 更改为console.log 以查看.click 是否是罪魁祸首,它似乎正在工作。我认为我的显示功能有问题,但我似乎无法弄清楚原因。

这里是jsFiddle。这是GitHub上的项目

问题数组

var quizQuestions =
[{
    question: "1. Who is Prime Minister of the United Kingdom?",
    choices: ["David Cameron", "Gordon Brown", "Winston Churchill", "Tony Blair"],
    correctAnswer:0
},
{
    question: "2. Who is Prime Minister of the United Kingdom?",
    choices: ["David Cameron", "Gordon Brown", "Winston Churchill", "Tony Blair"],
    correctAnswer:2
},
{
    question: "3. Who is Prime Minister of the United Kingdom?",
    choices: ["David Cameron", "Gordon Brown", "Winston Churchill", "Tony Blair"],
    correctAnswer:1
}];

JavaScript 代码 (jQuery)

$(document).ready(function(){
    var all = quizQuestions,
        q = $("#question"),
        c = $("#choices"),
        ans = [],
        current = 0;

    display(current);

    function display (id) {
        var question = all[id].question;
        var choices = all[id].choices;

        q.html(question);
        c.html(function(){
            var output = "<form>";
            for (var i = 0; i < choices.length; i++) {
                output += "<input type='radio' name='question" +id
                + "' value='" + choices[i] + "'> "
                + choices[i] + "<br>";
            };
            output += "</form>"
            // console.log(output);
            return output;
        });
    };

    function changeDisplay (dir) {
        if (dir == 'next' && current < all.length-1) current++;
        if (dir == 'prev' && current > 0) current--;
        display(current);
    }

    function answerQ (q, a) {
        ans[q] = a;
        console.log(ans);
    }

    $(":radio").change(function(){
        answerQ( $(this)[0].name, $(this).val() );
    });

    $("#previous").click(function (){ changeDisplay('prev'); });
    $("#next").click(function (){ changeDisplay('next'); });

    // console.log("all.length: " + all.length + " | ans: " + ans + " | current: " + current);
});

【问题讨论】:

  • 有一个console.log 我无法在小提琴上显示。它应该显示所选问题/答案的namevalue

标签: javascript jquery


【解决方案1】:

这很可能是因为事件没有被委托。加载页面时,您绑定点击事件。但是随着 dom 被操纵(元素被移除),事件被删除。为此,您必须使用 delegate

像这样:

$('.container').on('change', ':radio', function(){
    answerQ( $(this)[0].name, $(this).val() );
});

编辑:我建议您保存或隐藏答案,而不是覆盖它们。这样会更容易实现之前的功能。

【讨论】:

  • 他想知道更改处理程序,而不是点击处理程序,但同样的理论也适用。
  • 我认为$("#previous").click(function (){ changeDisplay('prev'); }); 是您所写内容的简写。我错了吗?
  • @jeanpier_re 不一样。 $("#previous").click 绑定到以“previous”为 id 的元素。其中“on”委托绑定到 body 元素并监听 #previous 上的单击事件。这样可以删除以前的事件并且仍然附加事件。
  • @TylerMarien 我错过了!更新了我的答案。我还将选择器缩小到 .container,因为 ":radio" 和 "body" 可能会针对其他事件 :) 谢谢!
【解决方案2】:

看起来当您转到下一组问题时,您会替换页面上每个单选按钮的 HTML。但是,您永远不会将点击处理程序分配给新的单选按钮。您最初在页面加载时对所有单选按钮执行此操作,但在更改显示后您不会将点击处理程序重新应用于单选按钮。

在您的 document.ready 处理程序中,您在底部附近有这个:

    $(":radio").change(function(){
        answerQ( $(this)[0].name, $(this).val() );
    });

但是在显示函数中(当你​​选择上一个或下一个时调用)你有这个:

        c.html(function(){
            var output = "<form>";
            for (var i = 0; i < choices.length; i++) {
                output += "<input type='radio' name='question" +id
                + "' value='" + choices[i] + "'> "
                + choices[i] + "<br>";
            };
            output += "</form>"
            // console.log(output);
            return output;
        });

不会向任何新的输入选项添加点击处理程序。

【讨论】:

  • 好点。你建议我如何做到这一点?我不完全确定如何处理这个问题。
  • 有几种方法可以做到。我可能会在表单中添加一个类,然后在我的 jquery 语句中使用选择器来应用更改 $(".options:radio").change(function(){ answerQ( $(this)[0].name , $(this).val() ); ));
【解决方案3】:

这就是问题所在,当您直接将“.click()”或“.change()”等侦听器添加到元素时,您只是专门为该对象设置了侦听器。要创建一个适用于当前页面上所有元素的侦听器,以及通过动态方式创建的任何未来元素(ajax,页面加载完成后通过 javascript 添加的新元素),您应该设置 document 级别“on”函数:

改变你在这里的东西:

$(":radio").change(function(){
    answerQ( $(this)[0].name, $(this).val() );
});

到这里:

$(document).on("change", ":radio", function(){
    answerQ($(this).name, $(this).val());
});

(我认为 $(this) 上的 [0] 没有任何意义,因为在那一刻它只适用于刚刚改变的元素)。

希望有帮助!

这里是进一步阅读该主题的链接:http://api.jquery.com/on/

【讨论】:

  • $(this)[0] 提取单选按钮的名称,以便我可以将其与所选答案相关联。似乎是我可以通过给定的数组实现这一目标的唯一方法。
  • 你说得对,对不起,我忘了这是一个单选按钮列表,所以从技术上讲它们都会改变。
【解决方案4】:

我会将显示函数移出 $(document).ready() 事件的回调方法。恕我直言,它属于全局空间,因为它被全局空间中的其他函数调用。它比依靠闭包来保持对隐藏在事件处理程序中的对象的引用更干净。

编辑:我想问题在于使用它,而无需单步执行代码。如果您在处理程序 .change() 中使用传递事件对象并使用它来获取对元素的引用,事情会发生变化吗?

【讨论】:

  • 使用“on()”函数可以工作,但使用“change()”就不行,除非脚本位于页面上相关元素的下方。 DOM 必须先渲染元素,然后才能分配这样的直接侦听器。这与纯 javascript 存在的问题相同,其中侦听文档加载完成确保所有元素都在 DOM 中。
  • 不小心删除了我之前的评论。感谢您的反馈,我会调查一下。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-23
  • 2014-02-24
  • 1970-01-01
  • 2013-03-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多