jQuery:检测是否在“更改”中单击了某个按钮事件处理程序

发布于 2024-12-09 13:17:46 字数 1430 浏览 0 评论 0原文

如果这很简单,请原谅我 - 我已经离开计算机和 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)
});

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

$('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
});

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

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

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

Forgive me if this is simple - I have been away from computers and JS for a month, so this task is seeming impossible to me, where I know it shouldn't be.

The quickest way I can think of explaining it is to put it in code, using comments to explain how it works. I'll indicate in these comments which is the part that I can't figure out.

I have a text field styled to look non-editable, with an 'edit' button next to it which, when clicked, turns into a 'save' button, and makes the text field look editable.

$(".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)
});

All that works fine. However, if the user leaves the editable text field I want to be able to detect whether they've left the field to click the 'save' button, or just clicked anywhere else on the page. So within the 'blur' event handler for the field, I need to know if I've clicked the 'save button. For the life of me I can't figure out how to do it:

$('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
});

So it's detecting if the save button was the reason for the 'blur' being triggered - that's what I can't figure out.

Or, if this is completely the wrong way of handling the situation, please let me know.

(I should point out that there could be many of these field/button combinations on the page, but so far that isn't affecting anything.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

坠似风落 2024-12-16 13:17:46

简介

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

输入图像描述这里

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

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

实现

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

在此处输入图像描述

实际解决方案(JS Fiddle 项目)

供参考我'我还包括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 调用都会有一个状态机(因为不同的输入按钮组可能处于不同的状态)。

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

结论

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

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

如果您发现错误或想到改进实施的方法,请随时对此答案发表评论。

Introduction

This is a very interesting (and non-trivial IMHO) problem. To solve it I first created a sample page that had multiple "groups" of text input boxes and buttons that enable them:

enter image description here

As per your question, the input box is disabled by default and made "editable" by clicking a button.

The best solution turned out to be a simple state machine. The state machine helps make sense of the (large amount of) events being fired by the browser by only looking at events that apply to the current state and ignoring all others.

Implementation

The following is a diagram of the state machine (text next to each transition arrow specifies the source and name of the event that triggers that transition):

enter image description here

Solution in action (JS Fiddle project)

For reference I'm also including the JavaScript code here:

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);
}

The code defines a single function, makeEditable. This function accepts ID of the input control and ID of the corresponding button that makes it editable. It then creates a closure with "private" state machine. This means that we will have one state machine per each makeEditable call (because different input-button groups may be in different states).

Actual "meat" of the state change handling (making the text box editable or disabled) can be found in setStateNow private function when current or new state is Locked.

Conclusion

I successfully tested the solution in Chrome 14, Opera 10.51, IE 9, FireFox 5.0.1, Safari 5.1, Mobile Safari (iPad2).

One UI behaviour that I would like to point out is an answer to a question What happens if the user presses the mouse button over the save button but while still holding the button leaves area of the button? In this case I decided to return back to Editable state and set focus to the input field again.

If you find bugs or think of a way to improve the implementation, please feel free to leave comments for this answer.

送君千里 2024-12-16 13:17:46

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

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

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

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

示例

我使用 setTimeout 引入了轻微的延迟,因为当单击按钮时,blur 事件总是在按钮的 click 事件之前首先触发。

I'm sure there is probably a much better solution, but here is what I came up with:

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

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

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

example here

I introduced a slight delay with setTimeout because it appears that when clicking on the button, the blur event always fires first before the button's click event.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文