Подтвердить что ты не робот

Как я могу настроить параметры плагина по умолчанию для окончательных настроек?

Я работаю над плагином 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 во внешней, самоисполняемой функции, это сделает ее доступной по умолчанию. Но объявление его там вызывает проблемы: если я использую свой плагин несколько раз на странице, экземпляры перепутают их настройки.
4b9b3361

Ответ 1

Любые попытки изменить область действия после факта обречены. В 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) }
}

Ответ 2

Переменная 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;

Ответ 3

Просто измените settings на this:

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

Что это!

EDIT: О! Я только что заметил что-то в вашем коде! Не используйте .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/