jQuery:检测在'change'事件处理程序中是否单击了某个按钮

时间:2011-10-11 03:06:33

标签: jquery click onchange blur

请原谅我,如果这很简单 - 我已经离开电脑和JS一个月了,所以这项任务对我来说似乎是不可能的,我知道它不应该是。

我能想到解释它的最快方法是将它放在代码中,使用注释来解释它是如何工作的。我将在这些评论中指出哪些是我无法弄清楚的部分。

我的文字字段看起来不可编辑,旁边有一个“编辑”按钮,点击后会变成“保存”按钮,并使文本字段看起来可编辑。

$(".edit_btn").click(function() {
   // make the associated text field look editable, and change this 'edit'
   // button into a 'save' button. Then place focus on the text in
   // in the field.
});

$(".save_btn").click(function() {
   // if (value in associated text field has changed from when page loaded)
   //   submit the form and save this new text
   // else 
   //   revert to non-editable mode (hide this 'save' button, 
   //   and show 'edit' button)
});

一切正常。但是,如果用户离开可编辑的文本字段,我希望能够检测他们是否已离开字段以单击“保存”按钮,或者只是单击页面上的任何其他位置。因此,在该字段的'blur'事件处理程序中,我需要知道是否已单击“保存”按钮。对于我的生活,我无法弄清楚如何做到这一点:

$('input[name^="tgfld_"]').blur(function() {
    // if (save button has been clicked) <- this is the problem
    //   don't do anything since the save function will handle this
    // else if (value in the field hasn't changed)
    //   revert everything back to non-editable mode
    // else if (value in the field HAS changed)
    //   do a window.confirm and prompt the user to click the 'save' 
    //   button to save their changes
});

所以它正在检测保存按钮是否是触发“模糊”的原因 - 这是我无法弄清楚的。

或者,如果处理这种情况完全是错误的方式,请告诉我。

(我应该指出页面上可能有很多这样的字段/按钮组合,但到目前为止并没有影响任何内容。)

2 个答案:

答案 0 :(得分:3)

简介

这是一个非常有趣(并且非平凡的恕我直言)问题。为了解决这个问题,我首先创建了一个示例页面,其中包含多个“组”文本输入框和按钮,用于启用它们:

enter image description here

根据您的问题,默认情况下禁用输入框,并通过单击按钮使其“可编辑”。

最好的解决方案原来是一个简单的状态机。状态机通过查看适用于当前状态的事件并忽略所有其他事件,帮助理解浏览器触发的(大量)事件。

实施

以下是状态机的图表(每个转换箭头旁边的文本指定触发该转换的事件的来源和名称):

enter image description here

Solution in action (JS Fiddle project)

作为参考,我还在这里包含JavaScript代码:

function makeEditable(inputId, btnId) {
    var state = "Locked", timeout = null, $input = $("#" + inputId), $btn = $("#" + btnId);

    function setStateNow(precondition, newState, e) {
        if (!precondition || state === precondition) {
            if (window.console) { window.console.log("State change: " + state + " => " + newState + " (from " + e.target.id + "." + e.type + ")"); }
            if (newState === "Locked") { // changing from any state to Locked
                $input.prop("disabled", true);
                $btn.val("Edit");
            } else if (state === "Locked") { // changing from Locked to any other state
                $input.prop("disabled", false).focus();
                $btn.val("Save");
            }
            if (newState === "LockPending") { // changing from any state to LockPending
                timeout = setTimeout(
                    function () { setStateNow("LockPending", "Locked", { target: { id: e.target.id }, type: "setTimeout" }); },
                    20);
            } else if (state === "LockPending") { // changing from LockPending to any other state
                if (timeout) {
                    clearTimeout(timeout);
                    timeout = null;
                }
            }
            if (newState === "Editable" && state === "LockPendingMouse") {
                $input.focus();
            }

            state = newState;
            return true;
        }
        return false;
    }


    function setState(e) {
        var r;
        if (e.data.rules) {
            for (i in e.data.rules) {
                r = e.data.rules[i];
                if (setStateNow(r.precondition, r.newState, e)) {
                    return;
                }
            }
        } else {
            setStateNow(e.data.precondition, e.data.newState, e);
        }
    }


    $input
        .focus ({ precondition: "LockPending", newState: "Editable" }, setState)
        .blur({ precondition: "Editable", newState: "LockPending" }, setState);

    $btn
        .click({ rules: [{ precondition: "Locked", newState: "Editable" }, { precondition: "LockPendingMouse", newState: "Locked" }, { precondition: "Editable", newState: "Locked" }] }, setState)
        .mousedown({ precondition: "Editable", newState: "LockPendingMouse" }, setState)
        .mouseleave({ precondition: "LockPendingMouse", newState: "Editable" }, setState)
        .focus ({ precondition: "LockPending", newState: "Editable" }, setState)
        .blur({ precondition: "Editable", newState: "LockPending" }, setState);
}

代码定义了一个函数makeEditable。此函数接受输入控件的ID和相应按钮的ID,使其可编辑。然后它使用“私有”状态机创建一个闭包。这意味着每个makeEditable调用我们将有一个状态机(因为不同的输入按钮组可能处于不同的状态)。

当前状态或新状态为setStateNow时,可以在Locked私有函数中找到状态更改处理的实际“肉”(使文本框可编辑或禁用)。

结论

我在Chrome 14,Opera 10.51,IE 9,FireFox 5.0.1,Safari 5.1,Mobile Safari(iPad2)中成功测试了该解决方案。

我想指出的一个UI行为是对问题的回答如果用户在保存按钮上按下鼠标按钮但仍然按住按钮会离开按钮区域会发生什么?在这种情况下,我决定返回可编辑状态并再次将焦点设置到输入字段。

如果您发现错误或想出改进实施的方法,请随时留下评论。

答案 1 :(得分:1)

我确信可能有更好的解决方案,但这就是我想出的:

$(document).ready(function() {
    saved = false;

    $('#button').click(function() {
        saved = true;
    });

    $('#input').blur(function() {
        var t = setTimeout("if(!saved) {alert('not saved!');}",400);
    }); 
});

example here

我使用setTimeout稍微延迟了一段时间,因为当点击按钮时,blur事件似乎总是在按钮的click事件之前触发。