Как создать плагин jQuery с помощью методов?
Я пытаюсь написать плагин jQuery, который предоставит дополнительные функции/методы объекту, который его вызывает. Все обучающие материалы, которые я читал в Интернете (были просмотрены в течение последних 2 часов), включают, самое большее, как добавлять параметры, но не дополнительные функции.
Вот что я хочу сделать:
//format div должен быть контейнером сообщений, вызывая плагин для этого div
$("#mydiv").messagePlugin();
$("#mydiv").messagePlugin().saySomething("hello");
или что-то в этом роде.
Вот что это сводится к: я вызываю плагин, а затем вызываю функцию, связанную с этим плагином. Я не могу найти способ сделать это, и я видел, как многие плагины делают это раньше.
Вот что у меня до сих пор для плагина:
jQuery.fn.messagePlugin = function() {
return this.each(function(){
alert(this);
});
//i tried to do this, but it does not seem to work
jQuery.fn.messagePlugin.saySomething = function(message){
$(this).html(message);
}
};
Как я могу достичь чего-то подобного?
Спасибо!
Обновление 18 ноября 2013 года. Я изменил правильный ответ на вопрос Хари, следуя комментариям и рекомендациям.
Ответы
Ответ 1
Согласно странице создания плагина jQuery (http://docs.jquery.com/Plugins/Authoring), лучше не испортить пространства имен jQuery и jQuery.fn. Они предлагают этот метод:
(function( $ ){
var methods = {
init : function(options) {
},
show : function( ) { },// IS
hide : function( ) { },// GOOD
update : function( content ) { }// !!!
};
$.fn.tooltip = function(methodOrOptions) {
if ( methods[methodOrOptions] ) {
return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
// Default to "init"
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.tooltip' );
}
};
})( jQuery );
В основном вы храните свои функции в массиве (привязаны к функции обертывания) и проверяете запись, если переданный параметр является строкой, возвращаясь к методу по умолчанию (здесь "init" ), если этот параметр является объектом (или нуль).
Затем вы можете вызвать такие методы...
$('div').tooltip(); // calls the init method
$('div').tooltip({ // calls the init method
foo : 'bar'
});
$('div').tooltip('hide'); // calls the hide method
$('div').tooltip('update', 'This is the new tooltip content!'); // calls the update method
Javascripts "arguments" variable - это массив всех переданных аргументов, поэтому он работает с произвольными значениями параметров функции.
Ответ 2
Вот шаблон, который я использовал для создания плагинов с дополнительными методами. Вы бы использовали его как:
$('selector').myplugin( { key: 'value' } );
или, чтобы вызвать метод напрямую,
$('selector').myplugin( 'mymethod1', 'argument' );
Пример:
;(function($) {
$.fn.extend({
myplugin: function(options,arg) {
if (options && typeof(options) == 'object') {
options = $.extend( {}, $.myplugin.defaults, options );
}
// this creates a plugin for each element in
// the selector or runs the function once per
// selector. To have it do so for just the
// first element (once), return false after
// creating the plugin to stop the each iteration
this.each(function() {
new $.myplugin(this, options, arg );
});
return;
}
});
$.myplugin = function( elem, options, arg ) {
if (options && typeof(options) == 'string') {
if (options == 'mymethod1') {
myplugin_method1( arg );
}
else if (options == 'mymethod2') {
myplugin_method2( arg );
}
return;
}
...normal plugin actions...
function myplugin_method1(arg)
{
...do method1 with this and arg
}
function myplugin_method2(arg)
{
...do method2 with this and arg
}
};
$.myplugin.defaults = {
...
};
})(jQuery);
Ответ 3
Как насчет этого подхода:
jQuery.fn.messagePlugin = function(){
var selectedObjects = this;
return {
saySomething : function(message){
$(selectedObjects).each(function(){
$(this).html(message);
});
return selectedObjects; // Preserve the jQuery chainability
},
anotherAction : function(){
//...
return selectedObjects;
}
};
}
// Usage:
$('p').messagePlugin().saySomething('I am a Paragraph').css('color', 'red');
Выбранные объекты сохраняются в закрытии messagePlugin, и эта функция возвращает объект, который содержит функции, связанные с плагином, в каждой функции вы можете выполнять требуемые действия для выбранных в данный момент объектов.
Вы можете протестировать и сыграть с кодом здесь.
Изменить: Обновлен код, чтобы сохранить силу цепочки jQuery.
Ответ 4
jQuery упростил это с введением Widget Factory.
Пример:
$.widget( "myNamespace.myPlugin", {
options: {
// Default options
},
_create: function() {
// Initialization logic here
},
// Create a public method.
myPublicMethod: function( argument ) {
// ...
},
// Create a private method.
_myPrivateMethod: function( argument ) {
// ...
}
});
Инициализация:
$('#my-element').myPlugin();
$('#my-element').myPlugin( {defaultValue:10} );
Вызов метода:
$('#my-element').myPlugin('myPublicMethod', 20);
(Так создается библиотека jQuery UI.)
Ответ 5
Проблема с выбранным в данный момент ответом заключается в том, что вы фактически не создаете новый экземпляр настраиваемого плагина для каждого элемента селектора, который, как вы думаете, вы делаете... вы на самом деле создаете только один экземпляр и прохождение в селекторе в качестве области действия.
Просмотрите эту скрипту для более глубокого объяснения.
Вместо этого вам нужно будет пропустить селектор с помощью jQuery.each и создать экземпляр нового экземпляра настраиваемого плагина для каждого элемента в селектор.
Вот как:
(function($) {
var CustomPlugin = function($el, options) {
this._defaults = {
randomizer: Math.random()
};
this._options = $.extend(true, {}, this._defaults, options);
this.options = function(options) {
return (options) ?
$.extend(true, this._options, options) :
this._options;
};
this.move = function() {
$el.css('margin-left', this._options.randomizer * 100);
};
};
$.fn.customPlugin = function(methodOrOptions) {
var method = (typeof methodOrOptions === 'string') ? methodOrOptions : undefined;
if (method) {
var customPlugins = [];
function getCustomPlugin() {
var $el = $(this);
var customPlugin = $el.data('customPlugin');
customPlugins.push(customPlugin);
}
this.each(getCustomPlugin);
var args = (arguments.length > 1) ? Array.prototype.slice.call(arguments, 1) : undefined;
var results = [];
function applyMethod(index) {
var customPlugin = customPlugins[index];
if (!customPlugin) {
console.warn('$.customPlugin not instantiated yet');
console.info(this);
results.push(undefined);
return;
}
if (typeof customPlugin[method] === 'function') {
var result = customPlugin[method].apply(customPlugin, args);
results.push(result);
} else {
console.warn('Method \'' + method + '\' not defined in $.customPlugin');
}
}
this.each(applyMethod);
return (results.length > 1) ? results : results[0];
} else {
var options = (typeof methodOrOptions === 'object') ? methodOrOptions : undefined;
function init() {
var $el = $(this);
var customPlugin = new CustomPlugin($el, options);
$el.data('customPlugin', customPlugin);
}
return this.each(init);
}
};
})(jQuery);
И рабочая скрипка.
Вы заметите, что в первой скрипте все div всегда перемещаются вправо с одинаковым количеством пикселей. Это связано с тем, что для всех элементов селектора существует только один объект параметров.
Используя технику, написанную выше, вы заметите, что во второй скрипте каждый div не выровнен и перемещается случайным образом (исключая первый div, поскольку он рандомизатор всегда установлен в 1 в строке 89). Это связано с тем, что теперь мы правильно создаем новый пользовательский экземпляр подключаемого модуля для каждого элемента селектора. Каждый элемент имеет свой собственный объект опций и не сохраняется в селекторе, но в экземпляре самого настраиваемого плагина.
Это означает, что вы сможете получить доступ к методам настраиваемого плагина, созданных на определенном элементе в DOM, из новых селекторов jQuery и не будут вынуждены кэшировать их, так как вы были бы в первом скрипте.
Например, это вернет массив всех объектов опций, используя технику во второй скрипке. Он вернет undefined в первый.
$('div').customPlugin();
$('div').customPlugin('options'); // would return an array of all options objects
Вот как вам нужно будет получить доступ к объекту options в первом скрипте и будет возвращать только один объект, а не массив из них:
var divs = $('div').customPlugin();
divs.customPlugin('options'); // would return a single options object
$('div').customPlugin('options');
// would return undefined, since it not a cached selector
Я бы предложил использовать вышеприведенный метод, а не тот, который был выбран в текущем ответе.
Ответ 6
Более простой подход - использовать вложенные функции. Затем вы можете связать их объектно-ориентированным способом. Пример:
jQuery.fn.MyPlugin = function()
{
var _this = this;
var a = 1;
jQuery.fn.MyPlugin.DoSomething = function()
{
var b = a;
var c = 2;
jQuery.fn.MyPlugin.DoSomething.DoEvenMore = function()
{
var d = a;
var e = c;
var f = 3;
return _this;
};
return _this;
};
return this;
};
И вот как это назвать:
var pluginContainer = $("#divSomeContainer");
pluginContainer.MyPlugin();
pluginContainer.MyPlugin.DoSomething();
pluginContainer.MyPlugin.DoSomething.DoEvenMore();
Будьте осторожны. Вы не можете вызвать вложенную функцию до тех пор, пока она не будет создана. Поэтому вы не можете этого сделать:
var pluginContainer = $("#divSomeContainer");
pluginContainer.MyPlugin();
pluginContainer.MyPlugin.DoSomething.DoEvenMore();
pluginContainer.MyPlugin.DoSomething();
Функция DoEvenMore даже не существует, поскольку функция DoSomething еще не запущена, что требуется для создания функции DoEvenMore. Для большинства плагинов jQuery у вас действительно будет только один уровень вложенных функций, а не два, как я показал здесь.
Просто убедитесь, что при создании вложенных функций, которые вы определяете эти функции в начале их родительской функции, прежде чем запускается какой-либо другой код в родительской функции.
Наконец, обратите внимание, что элемент "this" хранится в переменной с именем "_this". Для вложенных функций вы должны вернуть "_this", если вам нужна ссылка на экземпляр в вызывающем клиенте. Вы не можете просто вернуть "this" во вложенную функцию, потому что это вернет ссылку на функцию, а не на экземпляр jQuery. Возвращая ссылку на jQuery, вы можете возвращать встроенные методы jQuery.
Ответ 7
Я получил его из jQuery Plugin Boilerplate
Также описано в jQuery Plugin Boilerplate, повторите
// jQuery Plugin Boilerplate
// A boilerplate for jumpstarting jQuery plugins development
// version 1.1, May 14th, 2011
// by Stefan Gabos
// remember to change every instance of "pluginName" to the name of your plugin!
(function($) {
// here we go!
$.pluginName = function(element, options) {
// plugin default options
// this is private property and is accessible only from inside the plugin
var defaults = {
foo: 'bar',
// if your plugin is event-driven, you may provide callback capabilities
// for its events. execute these functions before or after events of your
// plugin, so that users may customize those particular events without
// changing the plugin code
onFoo: function() {}
}
// to avoid confusions, use "plugin" to reference the
// current instance of the object
var plugin = this;
// this will hold the merged default, and user-provided options
// plugin properties will be available through this object like:
// plugin.settings.propertyName from inside the plugin or
// element.data('pluginName').settings.propertyName from outside the plugin,
// where "element" is the element the plugin is attached to;
plugin.settings = {}
var $element = $(element), // reference to the jQuery version of DOM element
element = element; // reference to the actual DOM element
// the "constructor" method that gets called when the object is created
plugin.init = function() {
// the plugin final properties are the merged default and
// user-provided options (if any)
plugin.settings = $.extend({}, defaults, options);
// code goes here
}
// public methods
// these methods can be called like:
// plugin.methodName(arg1, arg2, ... argn) from inside the plugin or
// element.data('pluginName').publicMethod(arg1, arg2, ... argn) from outside
// the plugin, where "element" is the element the plugin is attached to;
// a public method. for demonstration purposes only - remove it!
plugin.foo_public_method = function() {
// code goes here
}
// private methods
// these methods can be called only from inside the plugin like:
// methodName(arg1, arg2, ... argn)
// a private method. for demonstration purposes only - remove it!
var foo_private_method = function() {
// code goes here
}
// fire up the plugin!
// call the "constructor" method
plugin.init();
}
// add the plugin to the jQuery.fn object
$.fn.pluginName = function(options) {
// iterate through the DOM elements we are attaching the plugin to
return this.each(function() {
// if plugin has not already been attached to the element
if (undefined == $(this).data('pluginName')) {
// create a new instance of the plugin
// pass the DOM element and the user-provided options as arguments
var plugin = new $.pluginName(this, options);
// in the jQuery version of the element
// store a reference to the plugin object
// you can later access the plugin and its methods and properties like
// element.data('pluginName').publicMethod(arg1, arg2, ... argn) or
// element.data('pluginName').settings.propertyName
$(this).data('pluginName', plugin);
}
});
}
})(jQuery);
Ответ 8
Слишком поздно, но может быть, это может помочь кому-то в один прекрасный день.
У меня была такая же ситуация, как создание плагина jQuery с некоторыми методами, и после прочтения некоторых статей и некоторых шин я создаю шаблон плагина jQuery (https://github.com/acanimal/jQuery-Plugin-Boilerplate).
Кроме того, я разрабатываю с ним плагин для управления тегами (https://github.com/acanimal/tagger.js) и написал два сообщения в блоге, объясняющих шаг за шагом создание плагина jQuery (http://acuriousanimal.com/blog/2013/01/15/things-i-learned-creating-a-jquery-plugin-part-i/).
Ответ 9
Как насчет использования триггеров? Кто-нибудь знает какой-либо недостаток, используя их?
Преимущество в том, что все внутренние переменные доступны через триггеры, а код очень прост.
Смотрите jsfiddle.
Пример использования
<div id="mydiv">This is the message container...</div>
<script>
var mp = $("#mydiv").messagePlugin();
// the plugin returns the element it is called on
mp.trigger("messagePlugin.saySomething", "hello");
// so defining the mp variable is not needed...
$("#mydiv").trigger("messagePlugin.repeatLastMessage");
</script>
Plugin
jQuery.fn.messagePlugin = function() {
return this.each(function() {
var lastmessage,
$this = $(this);
$this.on('messagePlugin.saySomething', function(e, message) {
lastmessage = message;
saySomething(message);
});
$this.on('messagePlugin.repeatLastMessage', function(e) {
repeatLastMessage();
});
function saySomething(message) {
$this.html("<p>" + message + "</p>");
}
function repeatLastMessage() {
$this.append('<p>Last message was: ' + lastmessage + '</p>');
}
});
}
Ответ 10
Здесь я хочу предложить шаги для создания простого плагина с аргументами.
JS
(function($) {
$.fn.myFirstPlugin = function( options ) {
// Default params
var params = $.extend({
text : 'Default Title',
fontsize : 10,
}, options);
return $(this).text(params.text);
}
}(jQuery));
Здесь мы добавили объект по умолчанию params
и задали значения по умолчанию для параметров с помощью функции extend
. Следовательно, если мы передаем пустой аргумент, тогда он будет устанавливать значения по умолчанию, иначе он будет установлен.
HTML
$('.cls-title').myFirstPlugin({ text : 'Argument Title' });
Подробнее: Как создать плагин JQuery
Ответ 11
Вот моя версия с голыми костями. Как и ранее, вы бы назвали:
$('#myDiv').MessagePlugin({ yourSettings: 'here' })
.MessagePlugin('saySomething','Hello World!');
- или напрямую обращаться к экземпляру @plugin_MessagePlugin
$elem = $('#myDiv').MessagePlugin();
var instance = $elem.data('plugin_MessagePlugin');
instance.saySomething('Hello World!');
MessagePlugin.js
;(function($){
function MessagePlugin(element,settings){ // The Plugin
this.$elem = element;
this._settings = settings;
this.settings = $.extend(this._default,settings);
}
MessagePlugin.prototype = { // The Plugin prototype
_default: {
message: 'Generic message'
},
initialize: function(){},
saySomething: function(message){
message = message || this._default.message;
return this.$elem.html(message);
}
};
$.fn.MessagePlugin = function(settings){ // The Plugin call
var instance = this.data('plugin_MessagePlugin'); // Get instance
if(instance===undefined){ // Do instantiate if undefined
settings = settings || {};
this.data('plugin_MessagePlugin',new MessagePlugin(this,settings));
return this;
}
if($.isFunction(MessagePlugin.prototype[settings])){ // Call method if argument is name of method
var args = Array.prototype.slice.call(arguments); // Get the arguments as Array
args.shift(); // Remove first argument (name of method)
return MessagePlugin.prototype[settings].apply(instance, args); // Call the method
}
// Do error handling
return this;
}
})(jQuery);
Ответ 12
Вы можете сделать:
(function ($) {
var YourPlugin = function (element, option) {
var defaults = {
//default value
}
this.option = $.extend({}, defaults, option);
this.$element = $(element);
this.init();
}
YourPlugin.prototype = {
init: function () {
},
show: function() {
},
//another functions
}
$.fn.yourPlugin = function (option) {
var arg = arguments,
options = typeof option == 'object' && option;;
return this.each(function () {
var $this = $(this),
data = $this.data('yourPlugin');
if (!data) $this.data('yourPlugin', (data = new YourPlugin(this, options)));
if (typeof option === 'string') {
if (arg.length > 1) {
data[option].apply(data, Array.prototype.slice.call(arg, 1));
} else {
data[option]();
}
}
});
};
});
Таким образом, ваш объект плагинов сохраняется как значение данных в вашем элементе.
//Initialization without option
$('#myId').yourPlugin();
//Initialization with option
$('#myId').yourPlugin({
//your option
});
//call show method
$('#myId').yourPlugin('show');
Ответ 13
Попробуйте следующее:
$.fn.extend({
"calendar":function(){
console.log(this);
var methods = {
"add":function(){console.log("add"); return this;},
"init":function(){console.log("init"); return this;},
"sample":function(){console.log("sample"); return this;}
};
methods.init(); // you can call any method inside
return methods;
}});
$.fn.calendar() // caller or
$.fn.calendar().sample().add().sample() ......; // call methods
Ответ 14
Фактически это можно сделать "хорошим" способом, используя defineProperty
. Где "хороший" означает без использования ()
, чтобы получить пространство имен плагинов или не передавать имя функции по строке.
Совместимость nit: defineProperty
не работает в старых браузерах, таких как IE8 и ниже.
Предостережение $.fn.color.blue.apply(foo, args)
не будет работать, вам нужно использовать foo.color.blue.apply(foo, args)
.
function $_color(color)
{
return this.css('color', color);
}
function $_color_blue()
{
return this.css('color', 'blue');
}
Object.defineProperty($.fn, 'color',
{
enumerable: true,
get: function()
{
var self = this;
var ret = function() { return $_color.apply(self, arguments); }
ret.blue = function() { return $_color_blue.apply(self, arguments); }
return ret;
}
});
$('#foo').color('#f00');
$('#bar').color.blue();
ссылка JSFiddle
Ответ 15
В соответствии со стандартом jquery вы можете создать плагин следующим образом:
(function($) {
//methods starts here....
var methods = {
init : function(method,options) {
this.loadKeywords.settings = $.extend({}, this.loadKeywords.defaults, options);
methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
$loadkeywordbase=$(this);
},
show : function() {
//your code here.................
},
getData : function() {
//your code here.................
}
} // do not put semi colon here otherwise it will not work in ie7
//end of methods
//main plugin function starts here...
$.fn.loadKeywords = function(options,method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(
arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not ecw-Keywords');
}
};
$.fn.loadKeywords.defaults = {
keyName: 'Messages',
Options: '1',
callback: '',
};
$.fn.loadKeywords.settings = {};
//end of plugin keyword function.
})(jQuery);
Как вызвать этот плагин?
1.$('your element').loadKeywords('show',{'callback':callbackdata,'keyName':'myKey'}); // show() will be called
Ссылка: ссылка
Ответ 16
Я думаю, это может помочь вам...
(function ( $ ) {
$.fn.highlight = function( options ) {
// This is the easiest way to have default options.
var settings = $.extend({
// These are the defaults.
color: "#000",
backgroundColor: "yellow"
}, options );
// Highlight the collection based on the settings variable.
return this.css({
color: settings.color,
backgroundColor: settings.backgroundColor
});
};
}( jQuery ));
Ответ 17
Ниже приведен небольшой плагин для использования метода предупреждения для отладки. Сохраните этот код в файле jquery.debug.js:
JS:
jQuery.fn.warning = function() {
return this.each(function() {
alert('Tag Name:"' + $(this).prop("tagName") + '".');
});
};
HTML:
<html>
<head>
<title>The jQuery Example</title>
<script type = "text/javascript"
src = "http://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src = "jquery.debug.js" type = "text/javascript"></script>
<script type = "text/javascript" language = "javascript">
$(document).ready(function() {
$("div").warning();
$("p").warning();
});
</script>
</head>
<body>
<p>This is paragraph</p>
<div>This is division</div>
</body>
</html>
Ответ 18
Вот как я это делаю:
(function ( $ ) {
$.fn.gridview = function( options ) {
..........
..........
var factory = new htmlFactory();
factory.header(...);
........
};
}( jQuery ));
var htmlFactory = function(){
//header
this.header = function(object){
console.log(object);
}
}
Ответ 19
Что вы сделали, это в основном расширение объекта jQuery.fn.messagePlugin с помощью нового метода. Это полезно, но не в вашем случае.
Вам нужно использовать эту технику
function methodA(args){ this // refers to object... }
function saySomething(message){ this.html(message); to first function }
jQuery.fn.messagePlugin = function(opts) {
if(opts=='methodA') methodA.call(this);
if(opts=='saySomething') saySomething.call(this, arguments[0]); // arguments is an array of passed parameters
return this.each(function(){
alert(this);
});
};
Но вы можете выполнить то, что хотите, я имею в виду, что есть способ сделать $( "# mydiv" ). messagePlugin(). saySomething ( "hello" ); Мой друг, он начал писать о lugins и о том, как продлить их с помощью вашей цепочки функций, вот ссылка на его блог