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