195

それを呼び出すオブジェクトに追加の関数/メソッドを提供するjQueryプラグインを作成しようとしています。私がオンラインで読んだすべてのチュートリアル(過去2時間閲覧しています)には、多くてもオプションを追加する方法が含まれていますが、追加の機能は含まれていません。

これが私がやろうとしていることです:

//その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);
  }
};

どうすればそのようなことを達成できますか?

ありがとうございました!


2013年11月18日更新:Hariの以下のコメントと賛成の正解を変更しました。

4

20 に答える 20

318

jQuery Plugin Authoring ページ ( 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 );

基本的には、関数を配列に格納し (ラッピング関数のスコープ)、渡されたパラメーターが文字列の場合はエントリをチェックし、パラメーターがオブジェクト (または null) の場合は既定のメソッド (ここでは「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" 変数は、渡されたすべての引数の配列であるため、任意の長さの関数パラメーターで機能します。

于 2011-07-29T10:33:10.590 に答える
56

これは、追加のメソッドを使用してプラグインを作成するために使用したパターンです。次のように使用します。

$('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);
于 2009-07-12T22:49:36.687 に答える
35

このアプローチはどうですか:

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 チェーン機能の機能を維持するためにコードを更新しました。

于 2009-07-12T23:27:46.797 に答える
18

現在選択されている回答の問題は、あなたがやっていると思うように、セレクターのすべての要素に対してカスタムプラグインの新しいインスタンスを実際に作成していないことです...実際には単一のインスタンスを作成して渡しているだけですスコープとしてのセレクター自体。

より深い説明については、このフィドルを参照してください。

代わりに、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 が常に正確に同じピクセル数だけ右に移動されることに気付くでしょう。これは、セレクター内のすべての要素に対してオプション オブジェクトが1 つしか存在しないためです。

上記の手法を使用すると、2 番目のフィドルで、各 div が整列されておらず、ランダムに移動されていることがわかります (ランダマイザーは常に 89 行で 1 に設定されているため、最初の div は除きます)。これは、セレクター内のすべての要素に対して新しいカスタム プラグイン インスタンスを適切にインスタンス化しているためです。すべての要素には独自のオプション オブジェクトがあり、セレクターには保存されませんが、カスタム プラグイン自体のインスタンスに保存されます。

これは、新しい jQuery セレクターから DOM の特定の要素でインスタンス化されたカスタム プラグインのメソッドにアクセスできることを意味し、最初のフィドルのようにそれらを強制的にキャッシュする必要はありません。

たとえば、これは 2 番目のフィドルの手法を使用して、すべてのオプション オブジェクトの配列を返します。最初は 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's not a cached selector

現在選択されている回答のものではなく、上記の手法を使用することをお勧めします。

于 2014-04-10T01:12:05.837 に答える
16

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ライブラリの構築方法です。)

于 2013-07-28T18:08:50.170 に答える
13

より簡単な方法は、ネストされた関数を使用することです。次に、それらをオブジェクト指向の方法で連鎖させることができます。例:

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 プラグインでは、実際には、ここで示したように 2 レベルではなく、1 レベルのネストされた関数しかありません。
ネストされた関数を作成するときは、親関数内の他のコードが実行される前に、親関数の先頭でこれらの関数を定義するようにしてください。

最後に、"this" メンバーが "_this" という変数に格納されていることに注意してください。ネストされた関数の場合、呼び出し元のクライアントでインスタンスへの参照が必要な場合は、"_this" を返す必要があります。ネストされた関数で「this」を返すことはできません。これは、jQuery インスタンスではなく関数への参照を返すためです。jQuery 参照を返すと、戻り時に組み込みの jQuery メソッドをチェーンできます。

于 2010-06-26T09:38:35.390 に答える
9

jQuery Plugin Boilerplateから取得しました

jQuery Plugin Boilerplate、repriseにも記載

// 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's 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's 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's 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's 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);
于 2014-06-23T05:55:26.990 に答える
6

手遅れですが、いつか誰かを助けることができるかもしれません。

私はいくつかの方法で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/ )。

于 2014-05-10T18:06:40.780 に答える
5

できるよ:

(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');
于 2016-03-07T06:28:34.350 に答える
2

これを試してください:

$.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
于 2014-06-30T17:42:17.200 に答える
1

これが私の最低限のバージョンです。前に投稿したものと同様に、次のように呼び出します。

$('#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);
于 2014-08-02T01:00:56.707 に答える
0

以下は、デバッグ用の警告メソッドを持つ小さなプラグインです。このコードを 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>
于 2016-02-16T08:11:56.467 に答える
0

これが私がそれを行う方法です:

(function ( $ ) {

$.fn.gridview = function( options ) {

    ..........
    ..........


    var factory = new htmlFactory();
    factory.header(...);

    ........

};

}( jQuery ));


var htmlFactory = function(){

    //header
     this.header = function(object){
       console.log(object);
  }
 }
于 2016-02-25T03:39:13.627 に答える
-2

あなたがしたことは、基本的にjQuery.fn.messagePlugin オブジェクトを new メソッドで拡張することです。これは便利ですが、あなたの場合ではありません。

あなたがしなければならないのは、このテクニックを使用することです

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 について書き始めた私の友人であり、機能のチェーンを使用してそれらを拡張する方法は、彼のブログへのリンクです。

于 2012-07-20T04:05:32.430 に答える