简体   繁体   English

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

[英]How can I give a plugin's default settings access to the final settings?

I'm working on a jQuery plugin. 我正在研究一个jQuery插件。 When the plugin runs, the first thing it does is determine its settings. 当插件运行时,它首先要确定它的设置。 It does this by taking some default settings and overriding some or all of them with whatever the user passed in. 它通过采用一些默认设置并使用用户传入的任何内容覆盖部分或全部设置来实现此目的。

Here's a simplified version: 这是一个简化版本:

(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 );

So, if you call the plugin like this: 所以,如果你像这样调用插件:

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

... you override the default alerter function, but use the default favoriteColor . ...您覆盖默认alerter功能,但使用默认的favoriteColor

I'm defining the defaults outside the plugin itself so that they are publicly accessible. 我在插件本身之外定义默认值,以便它们可以公开访问。 So if you want to change the default value for favoriteColor , you can just do this: 因此,如果您想更改favoriteColor默认值,您可以这样做:

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

... and that will change it for every instance on the page after that. ......之后,这会改变页面上每个实例的内容。

All of this works fine. 所有这一切都很好。

Here's my problem: in one of the default functions, I need to refer to settings . 这是我的问题:在其中一个默认函数中,我需要参考settings Something like this: 像这样的东西:

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

But when I try this, I get a Javascript error on the line where the default alerter function is declared: "settings is not defined." 但是当我尝试这个时,我在声明默认警报器功能的行上得到一个Javascript错误:“设置未定义”。 True enough: it's not defined yet when the parser hits that line. 确实如此:当解析器命中该行时,它尚未定义。 It WILL be defined by the time the function runs, but that doesn't seem to matter. 它将由函数运行的时间定义,但这似乎并不重要。

So my question is: How can I import my default function into the plugin in such a way that it has access to settings ? 所以我的问题是: 如何以一种可以访问settings的方式将我的默认功能导入插件?

  • Is there a way to delay evaluation of settings until the function is actually called? 有没有办法延迟settings评估,直到实际调用该函数?
  • If so, is there a way to make sure it has access to the local scope of the plugin, even though I assume that, as an object, this function is being passed by reference? 如果是这样,有没有办法确保它可以访问插件的本地范围,即使我假设,作为一个对象,这个函数是通过引用传递的? I know that I can alter the value of this inside a function by using someFunction.call(valueToUseForThis) , but I don't know whether I can alter its scope after the fact. 我知道我可以改变的值, this为通过功能里面someFunction.call(valueToUseForThis)但我不知道我是否能在事后改变其范围。

Some Stuff that Doesn't Work 一些不起作用的东西

  • Initially, it seemed that if I declared settings in the outer, self-executing function, that would make it available to the defaults. 最初,似乎如果我在外部自执行函数中声明了settings ,那么它将使其可用于默认值。 But declaring it there causes problems: if I use my plugin multiple times on a page, the instances get their settings mixed up. 但是在那里声明它会导致问题:如果我在页面上多次使用我的插件,则实例会将其设置混淆。

Any attempts to change scope after the fact are doomed. 任何事后改变范围的企图都注定要失败。 There's no dynamic scoping in JavaScript. JavaScript中没有动态范围。

Workaround 1. Pass settings to the alerter explicitly: 解决方法1.明确地将设置传递给警报器:

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

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

Workaround 2. Pass settings to the alerter implicitly: 解决方法2.隐式将设置传递给警报器:

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

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

Both solutions tested and work well with multiple uses of the plugin. 两种解决方案都经过测试,并且可以很好地使用插件。 If you have no plans for using this keyword in your alerter, you can use it for referencing settings. 如果您没有计划在警报器中使用this关键字,则可以将其用于引用设置。

The third valid solution , which you and fudgey mentioned, is to attach settings object to the DOM element itself: 你和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)
  }
} 

Extra fun. 额外的乐趣。 Emulating dynamic scope, aka don't do this 模拟动态范围, 也就是说不要这样做

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)

Usage in a plugin: 插件中的用法:

$.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) }
}

The settings variable is scoped to the $.fn.somePlugin function so it is not available outside of this, which is where you're trying to reference it in $.fn.somePlugin.defaults . settings变量的范围限定为$.fn.somePlugin函数,因此它在此之外不可用,这是您尝试在$.fn.somePlugin.defaults引用它的$.fn.somePlugin.defaults Can you not simply move the default object inside $.fn.somePlugin and declare it in there? 你能不能简单地在$.fn.somePlugin移动默认对象并在那里声明它?

Try this (code untested): 试试这个(代码未经测试):

(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 );

Edit : In light of your comment below, the simplest approach is probably to just move the declaration of settings up a level into the outer function - being locally scoped to this function, it will still be private to external callers. 编辑 :根据您在下面的评论,最简单的方法可能是将设置声明向上移动到外部函数 - 本地作用于此函数,它仍然是外部调用者的私有。 Revised code below: 修改后的代码如下:

(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;

Simply change settings to this : 简单地更改settingsthis

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

That's it! 而已!

EDIT: Oh! 编辑:哦! I just noticed something in your code! 我刚注意到你的代码中有些东西! Don't use .call() to call settings.alerter . 不要使用.call()来调用settings.alerter That changes the meaning of this . 改变的意思this Just call the method directly. 只需直接调用该方法即可。 If you must use .call() , pass in settings as the parameter for this . 如果你必须使用.call()传递settings作为参数this

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

Here's a complete working example based on your code: http://jsfiddle.net/gilly3/k2Eep/2/ 以下是基于您的代码的完整工作示例: http//jsfiddle.net/gilly3/k2Eep/2/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM