12

在我的 ASP.NET Web 应用程序中,我尝试使用 jQuery 创建一种通用方式,在用户进行更改后离开表单之前警告用户。相当标准的东西,但经过大量搜索后,我还没有找到一种有效的技术。

这是我目前所拥有的:

    addToPostBack = function(func) {
        var old__doPostBack = __doPostBack;
        if (typeof __doPostBack != 'function') {
            __doPostBack = func;
        } else {
            __doPostBack = function() {
                old__doPostBack();
                func();
            }
        }
    }

    var isDirty = false;

    $(document).ready(function() {
        addToPostBack(function() {
            alert("Postback detected.")
            clearDirty();
        });
        $(':input').bind("change select keydown", setDirty);
        window.onbeforeunload = function(e) {
            var msg = "You have unsaved changes. "
            if (isDirty == true) {
                var e = e || window.event;
                if (e) { e.returnValue = msg; }
                return msg;
            }
        };
    });

    setDirty = function() {isDirty = true;}

    clearDirty = function() {isDirty = false;}

这可以警告用户不要离开。问题是我在每个同页回发时都会收到警告。我的表单上有很多东西可能会触发回发:

  1. 页面上有保存、取消和删除链接按钮
  2. 页面上可能有其他链接按钮执行服务器端功能,同时停留在同一页面上
  3. 可能还有其他带有 autopostback=true 的控件也附加了服务器端功能,但不会导致用户离开页面。

这些事情都不应该引起警告,因为用户没有离开页面。我的代码试图劫持 addToPostBack (有关此问题的更多详细信息)以在回发之前清除 isDirty 位,但问题是在 IEonbeforeunload在 __doPostBack 之前触发,显然是因为 IE 在单击链接时立即触发 onbeforeunload (如此处所述)。

当然,我可以连接这些控件中的每一个以清除 isDirty 位,但我更喜欢在表单级别运行的解决方案,并且不需要我触摸每个可能触发回发的控件。

有没有人有一种适用于 ASP.NET 的方法,并且不涉及连接每个可能导致回发的控件?

4

5 回答 5

8

我在谷歌搜索在 MVC 中做同样事情的解决方案时遇到了这篇文章。这个改编自 Herb 的解决方案似乎效果很好。由于这没有任何 MVC 特定的内容,因此它应该同样适用于 PHP、Classic ASP 或任何其他类型的使用 HTML 和 JQuery 的应用程序。

var isDirty = false;

$(document).ready(function () {
    $(':input').bind("change select keydown", setDirty);
    $('form').submit(clearDirty);

    window.onbeforeunload = function (e) {
        var msg = "You have unsaved changes. "
        if (isDirty == true) {
            var e = e || window.event;
            if (e) { e.returnValue = msg; }
            return msg;
        }
    };
});

setDirty = function () { isDirty = true; }
clearDirty = function () { isDirty = false; }
于 2011-02-16T23:37:32.913 回答
2

很有趣,但是……你为什么不使用 jQuery 来做所有事情呢?

var  defaultSubmitControl = false;
var  dirty = false;
$(document).ready(function( ) {
    $('form').submit(function( ) { dirty = false });
    $(window).unload(function( ) {
        if ( dirty && confirm('Save?') ) {
            __doPastBack(defaultSubmitControl || $('form :submit[id]').get(0).id, '');
        }
    });
});
···
dirty = true;
···

现在,如果这仍然导致相同的问题(unload之前触发submit),您可以尝试不同的事件树,所以不要直接调用__doPostBack您...

setTimeout(function( ) {
    __doPastBack(defaultSubmitControl || $('form :submit[id]').get(0).id, '');
}, 1);  // I think using 0 (zero) works too

我还没有尝试过,这是我的想法,但我认为这可能是解决它的一种方法。

于 2010-02-06T00:36:28.317 回答
2

您始终可以创建一个继承的页面类,该类具有添加立即执行 JavaScript 的自定义OnLoad/OnUnload方法。

然后,您不必在控件特定级别处理它,而是在表单/页面级别处理它。

于 2009-08-05T18:52:14.753 回答
1

通过基本上跟踪鼠标位置来实现这一点。请记住,您仍然可以获得 Y 值的正值(因此我的代码行 < 50),但只要您的提交按钮向下超过 100 像素,您应该没问题。

这是我添加的用于跟踪鼠标更改并捕获 onbeforeunload 事件的 Javascript:

    <script language="JavaScript1.2">
    <!--

    // Detect if the browser is IE or not.
    // If it is not IE, we assume that the browser is NS.
    var IE = document.all?true:false

    // If NS -- that is, !IE -- then set up for mouse capture
    if (!IE) document.captureEvents(Event.MOUSEMOVE)

    // Set-up to use getMouseXY function onMouseMove
    document.onmousemove = getMouseXY;

    // Temporary variables to hold mouse x-y pos.s
    var tempX = 0
    var tempY = 0

    // Main function to retrieve mouse x-y pos.s

    function getMouseXY(e) {
      if (IE) { // grab the x-y pos.s if browser is IE
        tempX = event.clientX + document.body.scrollLeft
        tempY = event.clientY + document.body.scrollTop
      } else {  // grab the x-y pos.s if browser is NS
        tempX = e.pageX
        tempY = e.pageY
      }  
      // catch possible negative values in NS4
      if (tempX < 0){tempX = 0}
      if (tempY < 0){tempY = 0}  
      // show the position values in the form named Show
      // in the text fields named MouseX and MouseY
      document.Show.MouseX.value = tempX
      document.Show.MouseY.value = tempY
      return true
    }

    //-->
    </script>


    <script type="text/javascript">

        window.onbeforeunload = HandleOnClose;

        function HandleOnClose(e) {

            var posY = 0;
            var elem = document.getElementsByName('MouseY');
            if (elem[0]) {
                posY = elem[0].value;
            }

            if (posY < 50) {    // Your form "submit" buttons will hopefully be more than 100 pixels down due to movement
                return "You have not selected an option, are you sure you want to close?";
            }
        }

    </script>

然后只需将以下表单添加到您的页面上:

    <form name="Show">
        <input type="hidden" name="MouseX" value="0" size="4">
        <input type="hidden" name="MouseY" value="0" style="display:block" size="0">
    </form>

就是这样!它可以使用一点清理(删除 MouseX 等),但这在我现有的 ASP.net 3.5 应用程序中有效,并认为我会发布以帮助任何人。适用于 IE 7 和 Firefox 3.6,尚未尝试 Chrome。

于 2010-08-27T16:47:46.733 回答
0

我也在照顾这个,但到目前为止我发现的是,一个使用所有html 控件而不是 asp.net web 控件的解决方案,你想到了吗?

  <script type="text/javascript">
    $(document).ready(function () {
      $("form").dirty_form();
      $("#btnCancel").dirty_stopper();
    });             
  </script>
于 2010-05-18T14:00:22.610 回答