将异步 jQuery Dialog 更改为同步?

Posted

技术标签:

【中文标题】将异步 jQuery Dialog 更改为同步?【英文标题】:Change the asynchronous jQuery Dialog to be synchronous? 【发布时间】:2011-10-21 04:42:23 【问题描述】:

目前,我正在努力用 jquery 对话框替换“alert”/“confirm”。

但是大多数遗留代码都是以某种异步方式编写的,这使得更改变得困难。有什么方法可以使 jquery 对话框以同步方式工作? (不要使用循环或回调函数)

   For example:
   function run()
    
      var result = confirm("yes or no");
      alert( result );
      \\more codes here
   

在此示例中,警报和其他代码将在用户选择后执行。

如果我们使用 jquery 对话框 var 结果 = $dialog.open() 它将继续执行警报,这是异步的。

目前,我的解决方案是在 OK|Cancel 函数中使用回调函数。 例如:

    OK: function ()
   
       $dialog.close();
       alert("yes");
       //more codes here
    

这种方法可行,但是很难让所有同步代码都变成异步的,需要做很多改动(见下例)。 所以我在找同步的jQuery Dialog,可以吗??

例如:(实际代码比下面的例子复杂得多)

     function f1()
    
          if ( confirm("hello") )    f2();
          alert("no");
     

    function f2()
    
          if( confirm("world") )    f3();
          alert("no");
    

    function f3()
    
          return confirm("!") ;
    

另一个例子:

vendorObject.on('some-event', function() 
    if(confirm("Do you really want to do that?")) 
        return true;
    
    else 
        return false; // cancel the event
    
);

...这里供应商对象触发一个事件,如果用户确认,则必须取消该事件。只有当事件处理程序返回 false 时才能取消事件 - 同步。

【问题讨论】:

看看***.com/questions/887029/…,特别是评论***.com/questions/887029/… 他们已经不是重新发明***了;问题的核心是需要同步对话框。标准问题 jQuery 对话框倾向于使用回调。 @RichardJPLeGuen - 我已经编辑了我的答案以解决您添加的示例。可悲的是,简短的回答是,由于我的答案顶部列出的原因,让您的代码保持同步并使用自定义确认对话框简直是不可能 【参考方案1】:

简短的回答是否定的,您将无法保持代码同步。原因如下:

为了实现同步,当前执行的脚本必须等待用户提供输入,然后继续。 虽然有当前正在执行的脚本,但用户无法与 UI 交互。事实上,在脚本执行完成之前,UI 甚至不会更新。 如果脚本在用户提供输入之前无法继续,并且用户在脚本完成之前无法提供输入,那么您最接近的是浏览器挂起。

为了说明这种行为,调试您的代码并在更改 UI 的行之后的行上设置一个断点:

$("body").css("backgroundColor", "red");
var x = 1;  // break on this line

请注意,您的页面背景还不是红色。在您恢复执行并且脚本完成执行之前,它不会变为红色。当您使用调试器暂停脚本执行时,您也无法单击页面中的任何链接。

对于alert()confirm(),此规则有一个例外。这些是浏览器控件,其处理方式与实际网页 UI 元素不同。

好消息是转换您的代码真的应该不是很难。大概,您的代码目前看起来像这样:

if (confirm("continue?")) 
    // several lines of code if yes

else 
    // several lines of code if no

// several lines of code finally 

您的异步版本可以创建一个函数ifConfirm(text, yesFn, noFn, finallyFn),并且您的代码看起来非常相似:

ifConfirm("continue?", function () 
    // several lines of code if yes
,
function () 
    // several lines of code if no
,
function () 
    // several lines of code finally 
);

编辑:为了回应您添加到问题中的其他示例,不幸的是,该代码需要重构。 不可能有同步的自定义确认对话框。要在事件需要继续或取消的情况下使用自定义确认对话框,您只需始终取消该事件并在 yesFn 回调中模拟该事件。

例如一个链接:

$("a[href]").click(function (e) 
    e.preventDefault();
    var link = this.href;
    ifConfirm("Are you sure you want to leave this awesome page?", function () 
        location.href = link;
    );
);

或者,一种形式:

$("form").submit(function (e) 
    e.preventDefault();
    var form = this;
    ifConfirm("Are you sure you're ready to submit this form?", function () 
        form.submit();
    );
);

【讨论】:

不错!我最后也做了什么:D @gilly3 很棒的答案!恭喜!【参考方案2】:

我不确定不使用回调背后的动机是什么,因此很难判断哪种解决方案可能满足您的要求,但另一种延迟执行的方法是通过 jQuery 的“延迟”对象。

http://api.jquery.com/category/deferred-object/

您可以设置一个打开 jquery 对话框的函数并添加“等待”对话框关闭的代码。在您布置的情况下,这最终以与回调非常相似的方式工作,但这里有一个示例:

    function confirm () 
        var defer = $.Deferred(); 
        $('<div>Do you want to continue?</div>').dialog(
                autoOpen: true,
                close: function ()  
                    $(this).dialog('destroy');
                ,
                position: ['left', 'top'],
                title: 'Continue?',
                buttons: 
                    "Yes": function() 
                        defer.resolve("yes"); //on Yes click, end deferred state successfully with yes value
                        $( this ).dialog( "close" );
                    ,
                    "No": function() 
                        defer.resolve("no"); //on No click end deferred successfully with no value
                        $( this ).dialog( "close" );
                    
                
            );
        return defer.promise(); //important to return the deferred promise
    

    $(document).ready(function () 
        $('#prod_btn').click(function () 
            confirm().then(function (answer) //then will run if Yes or No is clicked
                alert('run all my code on '  + answer);

            );
        );

    );

它在 jsFiddle 中工作:http://jsfiddle.net/FJMuJ/

【讨论】:

问题在于无法更改的现有组件和接口取决于调用的同步性质。例如,我必须在事件处理程序中使用return false,具体取决于用户选择yesno 还是其他按钮。 您能否举一个更具体的例子来说明这些依赖项如何禁止使用回调或提到的其他解决方案?我并不完全清楚@gilly3 或我给出的答案如何不能满足您的需求。您将不得不使用在用户单击确认按钮时调用函数的结构。我认为在javascript中没有办法解决这个问题。这只是结构的问题。 不,你可能无法在 JavaScript 中解决这个问题。但是我以前也遇到过这个问题,我认为这是一个有趣的问题;想看看社区会提出什么解决方案。我将添加一个我遇到的问题的示例。【参考方案3】:

不,您不能在 Javascript 中进行任何同步操作(事实上,警告正在违反规则)。 Javascript 的核心是“单线程、异步”。

不过,您可以做的是禁用底层页面的功能(类似于灯箱),因此在您不执行对话框操作(确定或取消)之前,不会从页面触发任何事件。认为这不能帮助您使同步代码正常工作。你必须重写。

【讨论】:

【参考方案4】:

这里有一些想法 - 您真正想要的是阻止异步事件以使其看起来像同步。以下是一些链接:

Queuing async calls

Mobl

Narrative JavaScript

希望这可以进一步帮助您!

【讨论】:

【参考方案5】:

为了回答 David Whiteman 的更具体的问题,以下是我为 LinkBut​​ton Click 事件实现“延迟”回发的方式。基本上,我只是阻止默认行为并在用户反馈可用时手动触发回发。

function MyClientClickHandler(event, confirmationMessage, yesText, noText) 
    // My LinkButtons are created dynamically, so I compute the caller's ID
    var elementName = event.srcElement.id.replace(/_/g, '$');
    // I don't want the event to be fired immediately because I want to add a parameter based on user's input
    event.preventDefault();
    $('<p>' + confirmationMessage + '</p>').dialog(
        buttons: [
        
            text: yesText,
            click: function () 
                $(this).dialog("close");
                // Now I'm ready to fire the postback
                __doPostBack(elementName, 'Y');
            
        ,
        
            text: noText,
            click: function () 
                $(this).dialog("close");
                // In my case, I need a postback when the user presses "no" as well
                __doPostBack(elementName, 'N');
            
        
        ]
    );

【讨论】:

【参考方案6】:

您可以使用真正的模态对话框。

[dialog] 是网页中弹出框的元素,包括一个模态选项,该选项将使页面的其余部分在使用期间处于惰性状态。这对于阻止用户的交互直到他们给您响应或确认操作可能很有用。

https://github.com/GoogleChrome/dialog-polyfill

【讨论】:

【参考方案7】:

我真的不明白您为什么反对使用 Jquery 回调来实现示例中的行为。您肯定需要重写一些代码,例如:

    function f1()  
    $( "#testdiv" ).dialog(
        modal: true,
        buttons: 
            "OK": function() 
                $( this ).dialog( "close" );
                f2();
            ,
            Cancel: function() 
                $( this ).dialog( "close" );
                alert('no');
            
        
    );

function f2() 
      $( "#testdiv2" ).dialog(
        modal: true,
        buttons: 
            "OK": function() 
                $( this ).dialog( "close" );
                f3();
            ,
            Cancel: function() 
                $( this ).dialog( "close" );
                alert('no');
            
        
    );

function f3() 
    $( "#testdiv3" ).dialog(
        modal: true,
        buttons: 
            "OK": function() 
                $( this ).dialog( "close" );
            ,
            Cancel: function() 
                $( this ).dialog( "close" );
            
        
    );


    <div id="testdiv" title="Hello"/>
    <div id="testdiv2" title="World"/>
    <div id="testdiv3" title="!"/>

【讨论】:

以上是关于将异步 jQuery Dialog 更改为同步?的主要内容,如果未能解决你的问题,请参考以下文章

将 jquery UI 对话标题栏 HTML 从 span 更改为 H2

Dart 中的 stdout.write() 显然已从同步更改为异步,但我该如何使用它呢?

我可以将 jQuery UI 1.12.1 与 jQuery 3.x 一起使用吗?

如何使用jQuery将光标从指针更改为手指?

将 jQuery 更改为 ionic

如何将 Tkinter 按钮状态从禁用更改为正常?