如何为插件的默认设置提供对最终设置的访问权限?

时间:2011-02-16 11:27:32

标签: javascript jquery

我正在研究一个jQuery插件。当插件运行时,它首先要确定它的设置。它通过采用一些默认设置并使用用户传入的任何内容覆盖部分或全部设置来实现此目的。

这是一个简化版本:

(function( $ ) {
  $.fn.somePlugin = function(userOptions) {
    // Short name for internal use - exposed below for external modification
    var defaults = $.fn.somePlugin.defaults;

    // Decide settings
    // User settings overrule defaults, but merge both into an empty 
    // hash so that original defaults hash isn't modified
    var settings = $.extend(true, {}, defaults, userOptions);

    settings.alerter.call();

    // More code, etc.
  }

  $.fn.somePlugin.defaults = {
    name: 'Captain Slappy von Martinez, Esquire, DDS',
    favoriteColor: 'red',
    alerter: function(){alert("I got bones!");}        
  }

})( jQuery );

所以,如果你像这样调用插件:

    $('div').somePlugin({alerter: function(){alert('No bones here!');}});

...您覆盖默认的alerter函数,但使用默认的favoriteColor

我在插件本身之外定义默认值,以便它们可以公开访问。因此,如果您想更改favoriteColor默认值,您可以这样做:

$.fn.somePlugin.defaults.favoriteColor = 'blue';

...之后会为页面上的每个实例更改它。

所有这一切都很好。

这是我的问题:在其中一个默认函数中,我需要引用settings。像这样:

  $.fn.somePlugin.defaults = {
    name: 'Captain Slappy von Martinez, Esquire, DDS',
    favoriteColor: 'red',
    alerter: function(){alert("Paint me " + settings.favoriteColor);}        
  }

但是当我尝试这个时,我在声明默认警报器功能的行上遇到Javascript错误:“未定义设置”。确实如此:当解析器命中该行时,它尚未定义。它将由函数运行的时间定义,但这似乎并不重要。

所以我的问题是:如何将我的默认功能导入到插件中,使其可以访问settings

  • 有没有办法延迟settings的评估,直到实际调用该函数为止?
  • 如果是这样,有没有办法确保它可以访问插件的本地范围,即使我假设,作为一个对象,这个函数是通过引用传递的?我知道我可以使用this改变函数内someFunction.call(valueToUseForThis)的值,但我不知道是否可以在事后更改其范围。

一些不起作用的东西

  • 最初,似乎如果我在外部自执行函数中声明settings,那么它将使其可用于默认值。但是在那里声明它会导致问题:如果我在页面上多次使用我的插件,则实例会将其设置混淆。

3 个答案:

答案 0 :(得分:6)

事后注定改变范围的任何尝试都注定要失败。 JavaScript中没有动态范围。

解决方法1。 将设置明确传递给警报器:

$.fn.somePlugin = function(userOptions) {
  var settings = $.extend(...);
  settings.alerter(settings)
}

$.fn.somePlugin.defaults = {
  favoriteColor: 'red',
  alerter: function(settings) { alert("Paint me " + settings.favoriteColor) }
}

解决方法2. 隐式将设置传递给警报器:

$.fn.somePlugin = function(userOptions) {
  var settings = $.extend(...);
  settings.alerter()
}

$.fn.somePlugin.defaults = {
  favoriteColor: 'red',
  alerter: function() { alert("Paint me " + this.favoriteColor) }
}

这两个解决方案都经过测试,可以很好地使用插件。如果您没有计划在警报器中使用this关键字,则可以将其用于引用设置。

您和fudgey提到的第三个有效解决方案是将设置对象附加到DOM元素本身:

$.fn.somePlugin = function(userOptions) {
  var settings = $.extend(...);
  $(this).data('somePlugin', {settings: settings})
  settings.alerter.call(this)
}

$.fn.somePlugin.defaults = {
  favoriteColor: 'red',
  alerter: function() {
      alert("Paint me " + $(this).data('somePlugin').settings.favoriteColor)
  }
} 

额外的乐趣。模拟动态范围, a.k.a不要这样做

function dynamic(fn) {
  var parts = fn.toString().split('{')
  fn = parts.shift() + '{ with (args) { ' + parts.join('{') + '}'
  return {bind: function(args) { return eval('(' + fn + ')') }}
}

a = b = c = 0

function adder(c) {
  alert(a + b + c)
}

dynamic(adder).bind({a: 1, b: 2})(3) // alert(6)

插件中的用法:

$.fn.somePlugin = function(userOptions) {
  var settings = $.extend(...);
  dynamic(settings.alerter).bind({settings: settings})()
}

$.fn.somePlugin.defaults = {
  favoriteColor: 'red',
  alerter: function() { alert("Paint me " + settings.favoriteColor) }
}

答案 1 :(得分:3)

settings变量的范围限定为$.fn.somePlugin函数,因此它不在此范围之外,您可以在$.fn.somePlugin.defaults中尝试引用它。你能不能简单地移动$.fn.somePlugin中的默认对象并在那里声明它?

试试这个(代码未经测试):

(function( $ ) {
  $.fn.somePlugin = function(userOptions) {
    // Short name for internal use - exposed below for external modification
    var settings = {},
        defaults = {
            name: 'Captain Slappy von Martinez, Esquire, DDS',
            favoriteColor: 'red',
            alerter: function(){alert("Paint me " + settings.favoriteColor);}        
        };

    // Decide settings
    // User settings overrule defaults, but merge both into an empty 
    // hash so that original defaults hash isn't modified
    settings = $.extend(true, {}, defaults, userOptions);

    settings.alerter.call();

    // More code, etc.
  }

})( jQuery );

编辑:根据您在下面的评论,最简单的方法可能是将设置声明向上移动到外部函数中 - 在本地作用于此函数,它仍然是私人到外部呼叫者。修改后的代码:

(function( $ ) {

  var settings = {}

  $.fn.somePlugin = function(userOptions) {
    // Decide settings
    // User settings overrule defaults, but merge both into an empty 
    // hash so that original defaults hash isn't modified
    settings = $.extend(true, {}, $.fn.somePlugin.defaults, userOptions);

    settings.alerter.call();

    // More code, etc.
  }

  $.fn.somePlugin.defaults = {
      name: 'Captain Slappy von Martinez, Esquire, DDS',
      favoriteColor: 'red',
      alerter: function(){alert("Paint me " + settings.favoriteColor);}        
  }

})( jQuery );

$.fn.somePlugin.defaults.favoriteColor = 'blue';

$.fn.somePlugin(); // Should alert 'Paint me blue'

alert(settings.favoriteColour) // Will not work here;

答案 2 :(得分:2)

只需将settings更改为this

$.fn.somePlugin.defaults = {
    name: 'Captain Slappy von Martinez, Esquire, DDS',
    favoriteColor: 'red',
    alerter: function () { alert("Paint me " + this.favoriteColor); }        
}

就是这样!

编辑:哦!我刚注意到你的代码中有些东西!请勿使用.call()来致电settings.alerter。这改变了this的含义。只需直接调用该方法即可。如果您必须使用.call(),请传递settings作为this的参数。

settings.alerter.call();         // this won't work.
settings.alerter();              // but this will!
settings.alerter.call(settings); // this works too

以下是基于您的代码的完整工作示例:http://jsfiddle.net/gilly3/k2Eep/2/