尝试制作模态弹出菜单

Trying to make a modal popup menu

提问人:quilkin 提问时间:6/20/2013 更新时间:6/20/2013 访问量:1100

问:

我正在尝试创建一个模式弹出窗口(例如,用于是/否确认),以便在弹出窗口得到响应之前代码不会继续执行。我知道推荐的方法是为每个按钮(菜单项)添加回调,但是当菜单是循环的一部分并且其中一个结果可能是循环的“中断”而不是函数调用时,这种方法会出现问题。 无论如何,我在这里想出了代码,使用 jquery 1.3 弹出小部件:

var $popUp;
var popupResult;
function wait()
{
    if (popupResult == null) {
        setTimeout(wait, 100);
    }
    else
        return;
}

function CreatePopupMenu(title)
{
    popupResult = null;
    // for safety, timeout the popup if it isn't answered
    setTimeout(function(){ popupResult = false;  }, 3000);
    $popUp = $("<div/>").popup({
        dismissible: false,
        theme: "c",
        afteropen: function () {
            while (popupResult == null)
                wait();
        }
    }).on("popupafterclose", function ()
    {
        $(this).remove();
    });
    $("<h4/>", {  text: title }).appendTo($popUp);
}

问题是,弹出窗口实际上并没有出现,代码直接运行到“afteropen”回调中。如果弹出窗口未显示,则用户无法使用按钮设置“popupResult”,因此等待将永远持续。如果我删除“afteropen”回调,弹出窗口将按预期出现,但现在“popupResult”仍为 null(它将由在打开菜单之前附加到菜单的按钮上的回调设置)。 一个次要问题是,为什么我的“退出条款”没有触发更长的超时时间?

JavaScript jQuery

评论

0赞 hamstu 6/20/2013
您使用的是什么弹出库/小部件?
0赞 metadings 6/20/2013
请注意,在 JavaScript 中使用 double equals 运算符。只需使用 not 运算符,对于特殊检查,三元等于,例如 是 。!popupResult == false == null == undefined == 0 == '' == NaNnull !== false
0赞 quilkin 6/21/2013
我正在使用 jquery mobile 1.3.1。关于 == 运算符的好点,但这是一个简单的例子 - 我将把它改回来,以便 popupresult 可以是 0,1,2,etc,具体取决于按下的按钮

答:

0赞 Kyle Muir 6/20/2013 #1

你能使用 JQuery UI 吗?它带有自己的模态对话框。

http://jqueryui.com/dialog/#modal

评论

0赞 quilkin 6/21/2013
请参阅我上面对 @hamstu 的答案的评论,jquery Ui 对话框也依赖于按钮按下的回调,并且它们都继续处理到调用弹出窗口的点之后 - 它们不会等待答案,所以不是真正的模态(无论如何在我的意义上)
1赞 metadings 6/20/2013 #2

改变

afteropen: function () {
    while (popupResult == null)
        wait();
}

afteropen: wait

afteropen: function () { wait(); }

目前,您无休止地做,永远不会离开循环。这也会产生无限的超时。wait

使用您正在执行的更改一次“等待” - 这确实会重新设置Timeout,直到popupResult不再不是!


顺便说一句:这条线可能做不到,甚至干扰你的意图。如果浏览器在用户选择答案和下一个“等待”超时之间执行此操作 - 这将重置用户的更改。

setTimeout(function(){ popupResult = false;  }, 3000);

最好将 waitTimeout 保存在wait

var waitTimeout;

function wait() {
    if (!popupResult) {
        waitTimeout = setTimeout(wait, 100);
    }
}

因此,您可以执行并自动关闭弹出窗口:clearTimeout

setTimeout(function () {
    if (waitTimeout) {
        clearTimeout(waitTimeout);
        waitTimeout = undefined;
    }
    popupResult = undefined;
    $popUp.close();
}, 3000);

评论

0赞 quilkin 6/21/2013
删除 'while (popupResult == null)' 只会使弹出窗口返回 null 结果;它不会等待用户选择任何内容。关于我的 30000 超时的“退出条款”,虽然我只是把它作为尝试解决原始问题的一部分。
0赞 metadings 6/21/2013
我现在不明白你在哪里设置了“对话框的返回值”(我对 jQuery Mobile ;) 并不真正熟悉),但是没有设置或返回任何东西,而是无休止地循环,阻止任何进一步的执行 - javaScript 是单线程的 - 所以 setTimeout 会创建超时,但这些永远不会发生,直到你离开时间。while (popupResult == null)
2赞 hamstu 6/20/2013 #3

如前所述,您可能会找到解决问题的预制解决方案;那里有大量的jQuery模式弹出窗口和框(Google是你的朋友。也就是说,我至少可以看到一个问题:

$popUp = $("<div/>").popup({
  dismissible: false,
  theme: "c",
  afteropen: function () {
    /* while (popupResult == null) */ // <-- REMOVE THIS LINE
    wait();
  }
})

这个循环是不必要的。事实上,在这种情况下,你很少会想使用循环;你实际上是在启动一个无限循环(因为它会阻止其他代码的执行、浏览器渲染等)。尝试删除它,您的代码应该可以按预期更好地工作。(我还没有测试过。whilewhile


更好的方法是在HTML中构建弹出窗口,如下所示:(您也可以在jQuery中创建此代码,类似于您的示例)

<div class='popup' id='myPopup'>
  <h2>Popup Title</h2>
  <a href='#' class='action' data-action='close'>Close</a>
  <a href='#' class='action' data-action='other'>Press Me!</a>
</div>

然后,您只需将事件处理程序(即回调)附加到链接/按钮即可。

$('.popup a.action').on('click', function(event) {
   var action = $(this).data('action');
   // Do something... (Close popup, etc.)
});

我希望这是有道理的。

评论

0赞 quilkin 6/21/2013
是的,有许多可用的模式弹出窗口,但它们都需要对每个选定的项目进行回调,并且它们都允许在用户回答弹出窗口之前继续处理。例如,我们不能将“中断”(循环之外)作为回调。同样在我的情况下(通常是在一般情况下),在菜单弹出后还有进一步的处理,并且该处理取决于弹出的结果。
1赞 hamstu 6/21/2013
没有办法像你要求的那样暂停执行和等待;这在 JavaScript 中是不可能的,你必须使用回调,正如我所演示的那样。如果代码依赖于模式的结果,则将其放在不同的函数中,并在用户做出选择时调用该函数。
1赞 quilkin 6/21/2013
好的,谢谢,我现在接受我正在尝试的事情是不可能的;我只需要习惯这种单线程性(经过多年的 .NET 编码后很难!)并重构我的大部分代码。...