首页 > 解决方案 > 函数中的相同函数,保留变量/元素

问题描述

我正在创建一个创建模式的 javascript 函数。这是功能:

    function createModal(options) {
        var self = this;
        modalHeaderText = options.header;
        modalBodyText = options.body;
        $modal = $('<div />').addClass('modal').appendTo('body');
        $modalOverlay = $('<div />').addClass('modal-overlay').appendTo($modal);
        $modalContainer = $('<div />').addClass('modal-container').appendTo($modal);
        $modalHeader = $('<div />').addClass('modal-header').addClass(options.headerClass).html(modalHeaderText).appendTo($modalContainer);
        $modalBody = $('<div />').addClass('modal-body').addClass(options.bodyClass).html(modalBodyText).appendTo($modalContainer);
        if (options.buttons) {
            $modalFooter = $('<div />').addClass('modal-footer').appendTo($modalContainer);
            $.each(options.buttons, function(name, buttonOptions) {
                $modalButton = $('<button />').addClass(buttonOptions.class).html(name).appendTo($modalFooter);
                if(buttonOptions.callback) {
                    $modalButton.on('click', function() { 
                        buttonOptions.callback(); 
                    });
                } else {
                    $modalButton.on('click', function(e) { 
                        $modal.remove();
                    });
                };
            });
        };
        $modal.addClass('active');
        if (options.closeOnOverlayClick == true) {
            $modalOverlay.on('click', function(e) {
                $modal.remove();
            });
        };
    };

这很好用,但我希望能够在同一个函数中调用该函数,如下所示:

    $('#modal').on('click', function(e){
        e.preventDefault();
        createModal({
            header      : 'Enter your name',
            body        : '<input type="text" class="name" />',
            buttons     : {
                'OK'    : {
                    class : 'btn btn-success',
                    callback : function() {
                        var name = self.$modalBody.find('.name').val();
                        if (!name) {
                            createModal({
                                header      : 'Error',
                                body        : 'You must provide a name',
                                buttons     : {
                                    'OK'    : {
                                        class : 'btn'
                                    }
                                }
                            });
                        } else {
                            alert(name);
                        };
                    },
                },
                'Close' : {
                    class : 'btn btn-error'
                }
            }
        });
    });

我想要的是以下内容:当有人单击 ID 为“modal”(因此为“#modal”)的按钮时,会打开一个带有输入的模式。当按下 OK 按钮时,它会检查输入('name')是否有值。如果是这样,该值将显示在警报中。如果没有,一个新的模式是 openend(在当前模式之上),带有文本“你必须提供一个名称”。

如果我输入一个名字,它会起作用。该名称显示在警报中,并且关闭按钮也有效。但是如果我不输入名称,并且显示第二个模态,函数中的所有变量都会被覆盖。

如何保留第一个模式中的变量/元素,以便在显示(并清除)第二个模式后,第一个模式中的按钮仍然有效。

我在这里创建了一个 JSFiddle:https ://jsfiddle.net/6pq7ce0a/2/

你可以像这样测试它:

1)单击“打开模式” 2)输入名称 3)单击“确定” 4)名称显示在警报中 ==> 这有效

问题在这里:

1) 单击“打开模式” 2) 不要输入名称 3) 单击“确定” 4) 显示新模式 5) 在新(错误)模式中单击“确定” 6) 第一个按钮模态(带有输入字段)不再起作用

提前致谢!

更新

如果我将函数更改为下面的函数,则第一个模态根本不起作用。

    function createModal(options) {
        var self = this;
        var modalHeaderText = options.header;
        var modalBodyText = options.body;
        var $modal = $('<div />').addClass('modal').appendTo('body');
        var $modalOverlay = $('<div />').addClass('modal-overlay').appendTo($modal);
        var $modalContainer = $('<div />').addClass('modal-container').appendTo($modal);
        var $modalHeader = $('<div />').addClass('modal-header').addClass(options.headerClass).html(modalHeaderText).appendTo($modalContainer);
        var $modalBody = $('<div />').addClass('modal-body').addClass(options.bodyClass).html(modalBodyText).appendTo($modalContainer);
        if (options.buttons) {
            var $modalFooter = $('<div />').addClass('modal-footer').appendTo($modalContainer);
            $.each(options.buttons, function(name, buttonOptions) {
                var $modalButton = $('<button />').addClass(buttonOptions.class).html(name).appendTo($modalFooter);
                if(buttonOptions.callback) {
                    $modalButton.on('click', function() { 
                        buttonOptions.callback(); 
                    });
                } else {
                    $modalButton.on('click', function(e) { 
                        $modal.remove();
                    });
                };
            });
        };
        $modal.addClass('active');
        if (options.closeOnOverlayClick == true) {
            $modalOverlay.on('click', function(e) {
                $modal.remove();
            });
        };
    };

问题在这里:

var name = self.$modalBody.find('.name').val();

如果我将 'var' 添加到所有元素,则未定义 $modalBody。

标签: javascriptjquery

解决方案


因此,除了上面关于不声明的评论之外,var您还将引用存储window在 self 变量中。为了避免所有这些,我在这个小提琴中走上了这条路:https ://jsfiddle.net/10fanzw6/1/ 。

快速解释。

  • 首先不要按原样分配this给窗口selfthis
  • 其次将所有内容分配给空self对象以及本地变量(为了更好的可读性)
  • 第三次将selfvar 传递回任何按钮回调,让您可以访问您可能需要的模式的任何部分。

对于后代,包括此处的更新功能:

function createModal(options) {
  var self = {};
  var modalHeaderText = options.header;
  var modalBodyText = options.body;
  var $modal = self.$modal = $('<div />').addClass('modal').appendTo('body');
  var $modalOverlay = self.$modalOverlay = $('<div />').addClass('modal-overlay').appendTo($modal);
  var $modalContainer = self.$modalContainer = $('<div />').addClass('modal-container').appendTo(self.$modal);
  self.$modalHeader = $('<div />').addClass('modal-header').addClass(options.headerClass).html(modalHeaderText).appendTo($modalContainer);
  self.$modalBody = $('<div />').addClass('modal-body').addClass(options.bodyClass).html(modalBodyText).appendTo($modalContainer);
  if (options.buttons) {
    var $modalFooter = self.$modalFooter = $('<div />').addClass('modal-footer').appendTo($modalContainer);
    $.each(options.buttons, function(name, buttonOptions) {
      var $modalButton = $('<button />').addClass(buttonOptions.class).html(name).appendTo($modalFooter);
      if (buttonOptions.callback) {
        $modalButton.on('click', function() {
          buttonOptions.callback(self);
        });
      } else {
        $modalButton.on('click', function(e) {
          $modal.remove();
        });
      };
    });
  };
  $modal.addClass('active');
  if (options.closeOnOverlayClick == true) {
    $modalOverlay.on('click', function(e) {
      $modal.remove();
    });
  };
};
$('#modal').on('click', function(e) {
  e.preventDefault();
  createModal({
    header: 'Enter your name',
    body: '<input type="text" class="name" />',
    buttons: {
      'OK': {
        class: 'btn btn-success',
        callback: function(modal) {
          var name = modal.$modalBody.find('.name').val();
          if (!name) {
            createModal({
              header: 'Error',
              body: 'You must provide a name',
              buttons: {
                'OK': {
                  class: 'btn'
                }
              }
            });
          } else {
            alert(name);
          };
        },
      },
      'Close': {
        class: 'btn btn-error'
      }
    }
  });
});

推荐阅读