Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/456.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 自定义jQuery插件:事件行为不符合预期_Javascript_Events - Fatal编程技术网

Javascript 自定义jQuery插件:事件行为不符合预期

Javascript 自定义jQuery插件:事件行为不符合预期,javascript,events,Javascript,Events,我正在编写一个轻量级jQuery插件来检测脏表单,但在处理事件时遇到了一些问题。正如您在下面的代码中所看到的,该插件将一个事件侦听器附加到“beforeunload”上,该事件侦听器测试表单是否脏,并生成一个弹出窗口,如果是这样的话 还有一个附加到表单“提交”的事件侦听器,理论上应该删除该特定表单的“beforeunload”侦听器(即,我提交的当前表单不应该进行污垢测试,但页面上的其他表单应该进行测试) 我插入了一堆console.log语句来尝试调试它,但没有成功。想法 // Check

我正在编写一个轻量级jQuery插件来检测脏表单,但在处理事件时遇到了一些问题。正如您在下面的代码中所看到的,该插件将一个事件侦听器附加到“beforeunload”上,该事件侦听器测试表单是否脏,并生成一个弹出窗口,如果是这样的话

还有一个附加到表单“提交”的事件侦听器,理论上应该删除该特定表单的“beforeunload”侦听器(即,我提交的当前表单不应该进行污垢测试,但页面上的其他表单应该进行测试)

我插入了一堆console.log语句来尝试调试它,但没有成功。想法

  // Checks if any forms are dirty if leaving page or submitting another forms
  // Usage:
  // $(document).ready(function(){
  //    $("form.dirty").dirtyforms({
  //      excluded: $('#name, #number'),
  //      message: "please don't leave dirty forms around"
  //    });
  // });


  (function($) {

    ////// private variables //////

    var instances = [];

    ////// general private functions //////

    function _includes(obj, arr) {
        return (arr._indexOf(obj) != -1);
    }

    function _indexOf(obj) {
      if (!Array.prototype.indexOf) {
        Array.prototype.indexOf = function (obj, fromIndex) {
          if (fromIndex == null) {
            fromIndex = 0;
          } else if (fromIndex < 0) {
            fromIndex = Math.max(0, this.length + fromIndex);
          }
          for (var i = fromIndex, j = this.length; i < j; i++) {
            if (this[i] === obj)
            return i;
          }
          return -1;
        };
      }
    }

    ////// the meat of the matter //////

    // DirtyForm initialization
    var DirtyForm = function(form, options) {

      // unique name for testing purposes
      this.name = "instance_" + instances.length

      this.form = form;

      this.settings = $.extend({
        'excluded'  : [],
        'message'   : 'You will lose all unsaved changes.'
        }, options);

        // remember intial state of form
        this.memorize_current();

        // activate dirty tracking, but disable it if this form is submitted
        this.enable();
        $(this.form).on('submit', $.proxy(this.disable, this));

        // remember all trackable forms
        instances.push(this);
      }

      // DirtyForm methods
      DirtyForm.prototype = {

        memorize_current: function() {
          this.originalForm = this.serializeForm();
        },

        isDirty: function() {
          var currentForm = this.serializeForm();
          console.log("isDirty called...")
          return (currentForm != this.originalForm);
        },

        enable: function() {
          $(window).on('beforeunload', $.proxy(this.beforeUnloadListener, this));
          console.log("enable called on " + this.name)
        },

        disable: function(e) {
          $(window).off('beforeunload', $.proxy(this.beforeUnloadListener, this));
          console.log("disable called on " + this.name)
        },

        disableAll: function() {
          $.each(instances, function(index, instance) {
            $.proxy(instance.disable, instance)
          });
        },

        beforeUnloadListener: function(e) {
          console.log("beforeUnloadListener called on " + this.name)
          console.log("... and it is " + this.isDirty())
          if (this.isDirty()) {
            e.returnValue = this.settings.message;
            return this.settings.message;
          }
        },

        setExcludedFields: function(excluded) {
          this.settings.excluded = excluded;
          this.memorize_current();
          this.enable();
        },

        serializeForm: function() {
          var blacklist = this.settings.excludes
          var filtered = [];
          var form_elements = $(this.form).children();

          // if element is not in the excluded list
          // then let's add it to the list of filtered form elements
          if(blacklist) {
            $.each(form_elements, function(index, element) {
              if(!_includes(element, blacklist)) {
                filtered.push(element);
              }
            });
            return $(filtered).serialize(); 
          } else {
            return $(this.form).serialize();
          } 
        }
      };

      ////// the jquery plugin part //////

      $.fn.dirtyForms = function(options) {
        return this.each(function() {
          new DirtyForm(this, options);
        });
      };

    })(jQuery);

无论何时调用
$.proxy()
,它都会返回一个新的函数。因此,

$(window).off('beforeunload', $.proxy(this.beforeUnloadListener, this));
不会有任何效果,因为您正在尝试解除未绑定的函数的绑定

您必须存储对使用
$.proxy
创建的函数的引用,以便以后可以解除绑定:

enable: function() {
    this.beforeUnloadListener = $.proxy(DirtyForm.prototype.beforeUnloadListener, this);
    $(window).on('beforeunload', this.beforeUnloadListener);
    console.log("enable called on " + this.name)
},

disable: function(e) {
    $(window).off('beforeunload', this.beforeUnloadListener);
    console.log("disable called on " + this.name)
},

无论何时调用
$.proxy()
,它都会返回一个新的函数。因此,

$(window).off('beforeunload', $.proxy(this.beforeUnloadListener, this));
不会有任何效果,因为您正在尝试解除未绑定的函数的绑定

您必须存储对使用
$.proxy
创建的函数的引用,以便以后可以解除绑定:

enable: function() {
    this.beforeUnloadListener = $.proxy(DirtyForm.prototype.beforeUnloadListener, this);
    $(window).on('beforeunload', this.beforeUnloadListener);
    console.log("enable called on " + this.name)
},

disable: function(e) {
    $(window).off('beforeunload', this.beforeUnloadListener);
    console.log("disable called on " + this.name)
},

我在解决方案上领先了你大约5分钟,但我给你一个重点,因为这确实是正确的答案:D我最终得到了稍微不同的代码,但解决了你提到的问题。请看我在问题中的编辑。我在解决方案上领先了你大约5分钟,但我给你一个重点,因为这确实是正确的答案:D我最终使用了稍微不同的代码,但解决了你提到的问题。请看我在问题中的编辑。嗨,皮埃尔,你能在你的自定义插件上有一个实时演示吗。我真的很感激你发布的解决方案,当然@Roy,我刚刚上传了一个演示给Hi Pierre,你能在自定义插件上有一个实时演示吗。我真的很感激你发布的解决方案,当然@Roy,我刚刚上传了一个演示到