วิธีการสร้างปลั๊กอิน jQuery ด้วยวิธีการ?


191

ฉันกำลังพยายามเขียนปลั๊กอิน 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);
  }
};

ฉันจะทำสิ่งนี้ได้อย่างไร

ขอบคุณ!


อัปเดต 18 พ.ย. 2556: ฉันได้เปลี่ยนคำตอบที่ถูกต้องสำหรับคำติชมและ upvotes ต่อไปนี้ของ Hari

คำตอบ:


310

ตามหน้าการเขียนปลั๊กอิน 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" ที่นี่) หากพารามิเตอร์เป็นวัตถุ (หรือ null)

จากนั้นคุณสามารถเรียกวิธีการเช่นนั้น ...

$('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

ตัวแปร "อาร์กิวเมนต์" ของ Javascript เป็นอาร์เรย์ของอาร์กิวเมนต์ทั้งหมดที่ส่งผ่านดังนั้นจึงทำงานได้กับความยาวของพารามิเตอร์ฟังก์ชันโดยพลการ


2
นี่คือวิธีที่ฉันใช้ คุณยังสามารถเรียกใช้เมธอดแบบคงที่ผ่าน $ .fn.tooltip ('methodname', params);
Rake36

1
สถาปัตยกรรมที่มีประโยชน์มาก ฉันยังเพิ่มบรรทัดนี้ก่อนที่จะเรียกวิธีการเริ่มต้น: this.data('tooltip', $.extend(true, {}, $.fn.tooltip.defaults, methodOrOptions));ดังนั้นตอนนี้ฉันสามารถเข้าถึงตัวเลือกเมื่อใดก็ตามที่ฉันต้องการหลังจากการเริ่มต้น
ivkremer

16
สำหรับฉันคนแรกที่พูดว่า "ตัวแปรอาร์กิวเมนต์มาจากไหน" - developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ ...... - ฉันใช้ JS ตลอดไปและไม่เคยรู้มาก่อน คุณเรียนรู้สิ่งใหม่ทุกวัน!
Streetlogics

2
@DiH ฉันอยู่กับคุณในนี้ วิธีนี้ดูเหมือนดี initแต่มันไม่ได้ช่วยให้คุณเข้าถึงการตั้งค่าระดับโลกของคุณได้จากทุกที่อื่นที่ไม่ใช่
Stephen Collins

4
มีปัญหาใหญ่กับเทคนิคนี้! มันไม่ได้สร้างอินสแตนซ์ใหม่สำหรับทุกองค์ประกอบในตัวเลือกอย่างที่คุณคิดว่าคุณกำลังทำอยู่ แต่มันจะสร้างอินสแตนซ์เดียวที่แนบมากับตัวเลือกเท่านั้น ดูคำตอบของฉันสำหรับการแก้ปัญหา
Kevin Jurkowski

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

9
รูปแบบเดียวกันกับ jquery-ui ฉันไม่ชอบสายเวททั้งหมด แต่มีวิธีอื่น!
redsquare

8
ดูเหมือนว่าจะเป็นวิธีที่ไม่ได้มาตรฐานในการทำสิ่งต่าง ๆ - มีอะไรที่ง่ายไปกว่านี้เช่นฟังก์ชั่นผูกมัด? ขอบคุณ!
Yuval Karmi

2
@yuval - โดยทั่วไปแล้วปลั๊กอิน jQuery จะส่งคืน jQuery หรือค่าไม่ใช่ปลั๊กอินเอง นั่นเป็นเหตุผลที่ชื่อของวิธีการส่งผ่านเป็นอาร์กิวเมนต์ให้กับปลั๊กอินเมื่อคุณต้องการที่จะเรียกใช้ปลั๊กอิน คุณสามารถส่งผ่านจำนวนของการขัดแย้งใด ๆ แต่คุณจะต้องปรับฟังก์ชั่นและการแยกวิเคราะห์ อาจดีที่สุดในการตั้งค่าพวกเขาในวัตถุที่ไม่ระบุชื่อตามที่คุณแสดง
tvanfosson

1
ความหมายของคำ;ในบรรทัดแรกของคุณคืออะไร? กรุณาอธิบายให้ฉัน :)
GusDeCooL

4
@GusDeCooL เพียงตรวจสอบให้แน่ใจว่าเรากำลังเริ่มต้นคำสั่งใหม่เพื่อให้คำจำกัดความฟังก์ชั่นของเราไม่ได้ถูกตีความว่าเป็นอาร์กิวเมนต์สำหรับ Javascript ที่มีรูปแบบไม่ดีของคนอื่น (กล่าวคือการย่อส่วนเริ่มต้น ดูstackoverflow.com/questions/7365172/…
tvanfosson

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


1
ฉันมีเวลาค่อนข้างยากที่จะเข้าใจว่ามันจะเป็นอย่างไร สมมติว่าฉันมีรหัสที่จะต้องดำเนินการในครั้งแรกที่มีการเรียกใช้ฉันจะต้องเริ่มต้นมันในรหัสของฉัน - สิ่งเช่นนี้: $ ('p'). messagePlugin (); จากนั้นในโค้ดที่ฉันต้องการเรียกใช้ฟังก์ชัน saySomething เช่นนี้ $ ('p') messagePlugin (). saySomething ('something'); สิ่งนี้จะไม่เริ่มต้นปลั๊กอินใหม่แล้วเรียกใช้ฟังก์ชันหรือไม่ สิ่งนี้จะดูเหมือนกับสิ่งที่แนบมาและตัวเลือก? ขอบคุณมาก. -yuval
Yuval Karmi

1
การเรียงลำดับของการแบ่งกระบวนทัศน์ chainability ของ jQuery แม้ว่า
tvanfosson

บางทีนี่อาจเป็นคำตอบที่ดีที่สุด
Dragouf

3
ทุกครั้งที่คุณเรียก messagePlugin () มันจะสร้างวัตถุใหม่ที่มีทั้งสองฟังก์ชั่นใช่ไหม
w00t

4
ปัญหาหลักของวิธีนี้คือมันไม่สามารถรักษาความสามารถในการใช้งานต่อไปได้$('p').messagePlugin()เว้นแต่คุณจะเรียกใช้หนึ่งในสองฟังก์ชันที่ส่งคืน
Joshua Bambrick

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

และซอทำงาน

คุณจะสังเกตได้ว่าในซอครั้งแรก Divs ทั้งหมดจะถูกย้ายไปทางด้านขวาตามจำนวนพิกเซลที่แน่นอนเสมอ นั่นเป็นเพราะเพียงหนึ่งตัวเลือกวัตถุที่มีอยู่สำหรับทุกองค์ประกอบในตัวเลือก

เมื่อใช้เทคนิคที่เขียนไว้ด้านบนคุณจะสังเกตได้ว่าในซอตัวที่สองแต่ละ div ไม่เรียงตัวกันและจะถูกย้ายแบบสุ่ม (ยกเว้น div แรกเนื่องจากมันเป็นตัวสุ่มตั้งไว้ที่ 1 ในบรรทัดที่ 89) นั่นเป็นเพราะตอนนี้เรากำลังสร้างอินสแตนซ์ปลั๊กอินที่กำหนดเองใหม่สำหรับทุกองค์ประกอบในตัวเลือก ทุกองค์ประกอบมีอ็อพชั่นอ็อพชั่นของตัวเองและไม่ได้บันทึกในตัวเลือก, แต่ในอินสแตนซ์ของปลั๊กอินที่กำหนดเอง

ซึ่งหมายความว่าคุณจะสามารถเข้าถึงวิธีการของปลั๊กอินที่กำหนดเองที่สร้างอินสแตนซ์ในองค์ประกอบเฉพาะใน DOM จากตัวเลือก jQuery ใหม่และไม่ถูกบังคับให้แคชพวกเขาเนื่องจากคุณจะอยู่ในซอแรก

เช่นนี้จะส่งกลับอาร์เรย์ของวัตถุตัวเลือกทั้งหมดโดยใช้เทคนิคในซอที่สอง มันจะกลับมาไม่ได้กำหนดในครั้งแรก

$('div').customPlugin();
$('div').customPlugin('options'); // would return an array of all options objects

นี่คือวิธีที่คุณจะต้องเข้าถึงวัตถุตัวเลือกในซอครั้งแรกและจะคืนค่าวัตถุเดียวไม่ใช่อาร์เรย์ของพวกเขา:

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

ฉันขอแนะนำให้ใช้เทคนิคด้านบนไม่ใช่คำตอบที่เลือกในปัจจุบัน


ขอบคุณสิ่งนี้ช่วยฉันได้มากโดยเฉพาะการแนะนำวิธีการ. data () ให้ฉัน มีประโยชน์มาก FWIW คุณสามารถทำให้บางส่วนของรหัสของคุณง่ายขึ้นโดยใช้วิธีที่ไม่ระบุชื่อ
dalemac

jQuery chainability ไม่ทำงานโดยใช้วิธีการนี้ $('.my-elements').find('.first-input').customPlugin('update'‌​, 'first value').end().find('.second-input').customPlugin('update', 'second value'); returns Cannot read property 'end' of undefined... jsfiddle.net/h8v1k2pL
Alex G

16

jQuery ได้ทำมากนี้ง่ายขึ้นด้วยการเปิดตัวของโรงงาน Widget

ตัวอย่าง:

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


@ daniel.sedlacek a) "สถาปัตยกรรมที่แย่มาก" - เป็นเครื่องมือวิดเจ็ตมาตรฐานของ jQuery b) "ตรวจสอบความสมบูรณ์ของการรวบรวมเวลา" - JavaScript เป็นภาษาแบบไดนามิก c) "TypeScript" - wha?
Yarin

ก) นั่นคือเหตุผลที่โฆษณา
ป๊อปปูลา

นั่นคือความเข้าใจผิดอย่างแท้จริงนายเซดเลซ
mystrdat

ต่อเอกสาร: ระบบนี้เรียกว่า Widget Factory และเปิดเผยเป็น jQuery.widget โดยเป็นส่วนหนึ่งของ jQuery UI 1.8 อย่างไรก็ตามสามารถใช้ได้อย่างอิสระจาก jQuery UI $ .widget ใช้โดยไม่มี jQuery UI อย่างไร
Airn5475

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 ส่วนใหญ่คุณจะมีฟังก์ชันซ้อนกันเพียงระดับเดียวเท่านั้นและไม่ใช่สองอย่างที่ฉันได้แสดงไว้ที่นี่
เพียงให้แน่ใจว่าเมื่อคุณสร้างฟังก์ชั่นที่ซ้อนกันที่คุณกำหนดฟังก์ชั่นเหล่านี้ที่จุดเริ่มต้นของฟังก์ชั่นหลักของพวกเขาก่อนที่รหัสอื่น ๆ ในฟังก์ชั่นหลักได้รับการดำเนินการ

สุดท้ายโปรดทราบว่าสมาชิก "this" จะถูกเก็บไว้ในตัวแปรที่ชื่อว่า "_this" สำหรับฟังก์ชั่นที่ซ้อนกันคุณควรกลับ "_this" ถ้าคุณต้องการการอ้างอิงไปยังอินสแตนซ์ในลูกค้าโทร คุณไม่สามารถส่งคืน "this" ในฟังก์ชันซ้อนได้เนื่องจากจะส่งคืนการอ้างอิงไปยังฟังก์ชันไม่ใช่อินสแตนซ์ jQuery การส่งคืนการอ้างอิง jQuery อนุญาตให้คุณโยงเมธอด jQuery ที่แท้จริงกลับมาได้


2
นี่เป็นสิ่งที่ดี - ฉันสงสัยว่าทำไม jQuery ถึงชอบเรียกวิธีตามชื่อในรูปแบบ. plugin ('method')?
w00t

6
สิ่งนี้ใช้ไม่ได้ ถ้าคุณเรียกปลั๊กอินบนสองภาชนะที่แตกต่างกันตัวแปรภายในได้รับการแทนที่ (คือ _this)
mbrochh

ล้มเหลว: ไม่อนุญาตให้ใช้ pluginContainer.MyPlugin.DoEvenMore (). DoSomething ();
Paul Swetz

9

ฉันได้รับจาก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'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);

วิธีการของคุณแบ่ง jQuery chaining: $('.first-input').data('pluginName').publicMethod('new value').css('color', red);ส่งคืนCannot read property 'css' of undefined jsfiddle.net/h8v1k2pL/1
Alex G

@AlexG ให้ตัวอย่างนี้คุณจะเพิ่มreturn $elementในตัวอย่างนี้คุณจะเปลี่ยนเป็นplugin.foo_public_method = function() {/* Your Code */ return $element;}@Salim ขอบคุณที่ช่วยฉัน ... github.com/AndreaLombardo/BootSideMenu/pull/34
CrandellWS

6

สายเกินไป แต่บางทีมันอาจจะช่วยใครซักคนในหนึ่งวัน

ฉันอยู่ในสถานการณ์เดียวกันเช่นการสร้างปลั๊กอิน jQuery ด้วยวิธีการบางอย่างและหลังจากอ่านบทความบางส่วนและยางบางส่วนฉันสร้างแผ่นปลั๊กอินปลั๊กอิน jQuery ( https://github.com/acanimal/jQuery-Plugin-Boilerplate )

นอกจากนี้ฉันพัฒนาด้วยปลั๊กอินในการจัดการแท็ก ( https://github.com/acanimal/tagger.js ) และเขียนโพสต์ในบล็อกสองโพสต์เพื่ออธิบายขั้นตอนการสร้างปลั๊กอิน jQuery ( http: // acuriousanimal) com / บล็อก / 2013/01/15 / Things-i- เรียนรู้การสร้าง -a-jquery-plugin-part-i / )


อาจจะโพสต์ดีที่สุดที่ฉันได้เจอเลยเกี่ยวกับการสร้างปลั๊กอิน jQuery เป็นผู้เริ่มต้น - ขอบคุณ;)
Dex เดฟ

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

3

แล้วการใช้ทริกเกอร์ล่ะ? ไม่มีใครรู้ข้อเสียเปรียบใด ๆ ที่ใช้พวกเขา? ประโยชน์คือตัวแปรภายในทั้งหมดสามารถเข้าถึงได้ผ่านทริกเกอร์และรหัสนั้นง่ายมาก

เห็นใน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>

เสียบเข้าไป

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>');
        }

    });

}

1
cf เลย ความคิดเห็นของคุณ. ปัญหาเดียวที่ฉันเห็นในที่นี้คือการใช้ระบบเหตุการณ์ในทางที่ผิด มันผิดปกติที่จะใช้เหตุการณ์ล้วน ๆ เพื่อเรียกใช้ฟังก์ชัน ดูเหมือนว่า overkill และอาจแตกง่าย โดยปกติคุณจะใช้กิจกรรมในรูปแบบการสมัครรับข้อมูลเผยแพร่เช่นฟังก์ชั่นเผยแพร่ว่ามีเงื่อนไข "A" เกิดขึ้น หน่วยงานอื่น ๆ ที่สนใจ "A" ฟังข้อความที่เกิดขึ้นว่า "A" จากนั้นทำบางสิ่ง ดูเหมือนว่าคุณจะใช้มันเป็นคำสั่ง "กด" แทน แต่สมมติว่ามีผู้ฟังเพียงคนเดียว คุณต้องการระวังว่าซีแมนติกส์ของคุณจะไม่ถูกเพิ่มเข้ามา
tvanfosson

@tvanfosson ขอบคุณสำหรับความคิดเห็นของคุณ ฉันเข้าใจว่ามันไม่ใช่เทคนิคทั่วไปและอาจทำให้เกิดปัญหาได้หากมีคนเพิ่มผู้ฟังเหตุการณ์โดยไม่ตั้งใจ แต่ถ้าตั้งชื่อตามปลั๊กอินก็ไม่น่าเป็นไปได้ ฉันไม่รู้เกี่ยวกับปัญหาเกี่ยวกับประสิทธิภาพการทำงานใด ๆ แต่รหัสตัวเองดูเหมือนจะง่ายกว่าฉันกับโซลูชันอื่น ๆ แต่ฉันอาจพลาดบางสิ่งบางอย่าง
István Ujj-Mészáros

3

ที่นี่ฉันต้องการแนะนำขั้นตอนในการสร้างปลั๊กอินอย่างง่ายพร้อมอาร์กิวเมนต์

(function($) {
  $.fn.myFirstPlugin = function(options) {
    // Default params
    var params = $.extend({
      text     : 'Default Title',
      fontsize : 10,
    }, options);
    return $(this).text(params.text);
  }
}(jQuery));

$('.cls-title').myFirstPlugin({ text : 'Argument Title' });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1 class="cls-title"></h1>

ที่นี่เราได้เพิ่มวัตถุเริ่มต้นที่เรียกว่าparamsและตั้งค่าเริ่มต้นของตัวเลือกการใช้extendฟังก์ชั่น ดังนั้นถ้าเราผ่านอาร์กิวเมนต์ที่ว่างเปล่ามันจะตั้งค่าเริ่มต้นแทนมิฉะนั้นมันจะตั้ง

อ่านเพิ่มเติม: วิธีสร้างปลั๊กอิน JQuery


สวัสดี Gopal Joshi โปรดให้การสร้างปลั๊กอิน jquery ในระดับถัดไป เราคาดหวังจากคำตอบที่คุณต้องการ
Sakthi Karthik

สวัสดี @ SakthiKarthik, ปิด cource ฉันจะเผยแพร่บทช่วยสอนใหม่ในเร็ว ๆ นี้ในบล็อกของฉัน
Gopal Joshi

1
สวัสดี @ SakthiKarthik คุณสามารถดูบทความใหม่เกี่ยวกับ jquery plugin ระดับถัดไปที่นี่sgeek.org/…
Gopal Joshi

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

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

1

โครงสร้างปลั๊กอินต่อไปนี้ใช้jQuery- data()-methodเพื่อให้ส่วนต่อประสานสาธารณะกับปลั๊กอินภายใน / วิธีตั้งค่า (ในขณะที่รักษา jQuery-chainability):

(function($, window, undefined) { 
  const defaults = {
    elementId   : null,
    shape       : "square",
    color       : "aqua",
    borderWidth : "10px",
    borderColor : "DarkGray"
  };

  $.fn.myPlugin = function(options) {
    // settings, e.g.:  
    var settings = $.extend({}, defaults, options);

    // private methods, e.g.:
    var setBorder = function(color, width) {        
      settings.borderColor = color;
      settings.borderWidth = width;          
      drawShape();
    };

    var drawShape = function() {         
      $('#' + settings.elementId).attr('class', settings.shape + " " + "center"); 
      $('#' + settings.elementId).css({
        'background-color': settings.color,
        'border': settings.borderWidth + ' solid ' + settings.borderColor      
      });
      $('#' + settings.elementId).html(settings.color + " " + settings.shape);            
    };

    return this.each(function() { // jQuery chainability     
      // set stuff on ini, e.g.:
      settings.elementId = $(this).attr('id'); 
      drawShape();

      // PUBLIC INTERFACE 
      // gives us stuff like: 
      //
      //    $("#...").data('myPlugin').myPublicPluginMethod();
      //
      var myPlugin = {
        element: $(this),
        // access private plugin methods, e.g.: 
        setBorder: function(color, width) {        
          setBorder(color, width);
          return this.element; // To ensure jQuery chainability 
        },
        // access plugin settings, e.g.: 
        color: function() {
          return settings.color;
        },        
        // access setting "shape" 
        shape: function() {
          return settings.shape;
        },     
        // inspect settings 
        inspectSettings: function() {
          msg = "inspecting settings for element '" + settings.elementId + "':";   
          msg += "\n--- shape: '" + settings.shape + "'";
          msg += "\n--- color: '" + settings.color + "'";
          msg += "\n--- border: '" + settings.borderWidth + ' solid ' + settings.borderColor + "'";
          return msg;
        },               
        // do stuff on element, e.g.:  
        change: function(shape, color) {        
          settings.shape = shape;
          settings.color = color;
          drawShape();   
          return this.element; // To ensure jQuery chainability 
        }
      };
      $(this).data("myPlugin", myPlugin);
    }); // return this.each 
  }; // myPlugin
}(jQuery));

ตอนนี้คุณสามารถเรียกวิธีการปลั๊กอินภายในเพื่อเข้าถึงหรือแก้ไขข้อมูลปลั๊กอินหรือองค์ประกอบที่เกี่ยวข้องโดยใช้ไวยากรณ์นี้:

$("#...").data('myPlugin').myPublicPluginMethod(); 

ตราบใดที่คุณส่งคืนองค์ประกอบปัจจุบัน (นี้) จากภายในการใช้งานmyPublicPluginMethod()jQuery-chainability ของคุณจะถูกเก็บไว้ - ดังนั้นงานต่อไปนี้:

$("#...").data('myPlugin').myPublicPluginMethod().css("color", "red").html("...."); 

นี่คือตัวอย่าง (สำหรับรายละเอียดชำระเงินซอนี้):

// initialize plugin on elements, e.g.:
$("#shape1").myPlugin({shape: 'square', color: 'blue', borderColor: 'SteelBlue'});
$("#shape2").myPlugin({shape: 'rectangle', color: 'red', borderColor: '#ff4d4d'});
$("#shape3").myPlugin({shape: 'circle', color: 'green', borderColor: 'LimeGreen'});

// calling plugin methods to read element specific plugin settings:
console.log($("#shape1").data('myPlugin').inspectSettings());    
console.log($("#shape2").data('myPlugin').inspectSettings());    
console.log($("#shape3").data('myPlugin').inspectSettings());      

// calling plugin methods to modify elements, e.g.:
// (OMG! And they are chainable too!) 
$("#shape1").data('myPlugin').change("circle", "green").fadeOut(2000).fadeIn(2000);      
$("#shape1").data('myPlugin').setBorder('LimeGreen', '30px');

$("#shape2").data('myPlugin').change("rectangle", "red"); 
$("#shape2").data('myPlugin').setBorder('#ff4d4d', '40px').css({
  'width': '350px',
  'font-size': '2em' 
}).slideUp(2000).slideDown(2000);              

$("#shape3").data('myPlugin').change("square", "blue").fadeOut(2000).fadeIn(2000);   
$("#shape3").data('myPlugin').setBorder('SteelBlue', '30px');

// etc. ...     

0

นี้สามารถจริงจะทำให้การทำงานใน "ความสุข" definePropertyวิธีใช้ ที่ "ดี" หมายถึงโดยไม่ต้องใช้()เพื่อรับปลั๊กอิน namespace หรือไม่ต้องส่งชื่อฟังก์ชั่นโดยสตริง

ความเข้ากันได้ 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


0

ตามมาตรฐาน 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

อ้างอิง: ลิงค์


0

ฉันคิดว่านี่อาจช่วยคุณ ...

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

ในตัวอย่างข้างต้นฉันได้สร้างปลั๊กอินjquery highlight ที่เรียบง่ายฉันได้แชร์บทความที่ฉันได้พูดคุยเกี่ยวกับวิธีสร้างปลั๊กอิน jQuery ของคุณเองจากระดับพื้นฐานถึงระดับสูง ฉันคิดว่าคุณควรลองดู ... http://mycodingtricks.com/jquery/how-to-create-your-own-jquery-plugin/


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>

0

นี่คือวิธีที่ฉันทำ:

(function ( $ ) {

$.fn.gridview = function( options ) {

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


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

    ........

};

}( jQuery ));


var htmlFactory = function(){

    //header
     this.header = function(object){
       console.log(object);
  }
 }

-2

สิ่งที่คุณทำคือขยายวัตถุ 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 และวิธีเพิ่มพวกเขาด้วยฟังก์ชันการทำงานของ chain ที่นี่คือลิงค์ไปยังบล็อกของเขา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.