2009-10-07 4 views
5

Ich versuche, ein jQuery-Plugin zu erstellen, das etwas wie eine AutoCompleteBox, aber mit benutzerdefinierten Features erstellen wird. Wie speichere ich Mitgliedsvariablen für jedes passende jQuery-Element?Wie haben Sie Member-Variablen und öffentliche Methoden in einem jQuery-Plugin?

Zum Beispiel muss ich eine TimerID für jedes speichern. Ich möchte auch Referenzen auf einige der DOM-Elemente speichern, die das Steuerelement ausmachen.

Ich möchte in der Lage sein, eine öffentliche Methode zu machen, dass so etwas funktioniert:

$("#myCtrl").autoCompleteEx.addItem("1"); 

Aber bei der Umsetzung der addItem(), wie kann ich die Elementvariablen für das jeweilige Objekt wie seine timerId zugreifen oder Wasauchimmer?

Unten ist das, was ich bisher ...

Vielen Dank für jede Hilfe oder Anregungen!

(function($) 
{  
    //Attach this new method to jQuery 
    $.fn.autoCompleteEx = function(options) 
    {  
     //Merge Given Options W/ Defaults, But Don't Alter Either 
     var opts = $.extend({}, $.fn.autoCompleteEx.defaults, options); 


     //Iterate over the current set of matched elements 
     return this.each(function() 
     { 
      var acx = $(this); //Get JQuery Version Of Element (Should Be Div) 

      //Give Div Correct Class & Add <ul> w/ input item to it 
      acx.addClass("autoCompleteEx"); 
      acx.html("<ul><li class=\"input\"><input type=\"text\"/></li></ul>"); 

      //Grab Input As JQ Object 
      var input = $("input", acx); 

      //Wireup Div 
      acx.click(function() 
      { 
       input.focus().val(input.val()); 
      }); 


      //Wireup Input 
      input.keydown(function(e) 
      { 
       var kc = e.keyCode; 
       if(kc == 13) //Enter 
       { 

       } 
       else if(kc == 27) //Esc 
       { 

       } 
       else 
       { 
        //Resize TextArea To Input 
        var width = 50 + (_txtArea.val().length*10); 
        _txtArea.css("width", width+"px");  
       } 
      }); 

     }); //End Each JQ Element 

    }; //End autoCompleteEx() 

    //Private Functions 
    function junk() 
    { 

    }; 

    //Public Functions 
    $.fn.autoCompleteEx.addItem = function(id,txt) 
    { 
     var x = this; 
     var y = 0; 
    }; 

    //Default Settings 
    $.fn.autoCompleteEx.defaults = 
    { 
     minChars: 2, 
     delay:  300, 
     maxItems: 1 
    }; 

    //End Of Closure 
})(jQuery); 

Antwort

7

ich, dass die jQuery UI Art und Weise des Umgangs mit diesem zu arbeiten, scheint die besten gefunden habe. Sie erstellen Ihre 'Extra Methoden' als String-Argument, um das Plugin:

$('#elem').autoCompleteEx('addItem', '1'); 

Dann wird die 'this' Kontext erhalten bleibt, und Sie können in dieser Richtung etwas tun:

function addItem() { 
    // this should be == jquery object when this get called 
} 

$.fn.autoCompleteEx = function(options) { 
    if (options === 'addItem') { 
    return addItem.apply(this, Array.prototype.splice.call(arguments, 1)); 
    } 
}; 
+0

Sie sind ein Genie ... Tausend Dank dafür! – Legend

1

Werfen Sie einen Blick auf die .data Funktionalität von jQuery. Sie können Schlüssel/Wert-Paare für jedes Objekt speichern.

+0

Ja, das sieht aus wie es für mich trainieren. Weißt du, ob das die bevorzugte Methode für das ist, was ich erreichen will? – user169867

+0

Ein Nachteil ist, dass die Daten nicht privat sind. – user169867

1

Verwendung so etwas wie dieses:

acx.data("acx-somename", datavalue); 

Dann können Sie später abrufen mit:

var datavalue = acx.data("acx-somename"); 
+0

Da Daten von allen Daten gemeinsam genutzt werden, die mit dem betreffenden DOM-Objekt in Beziehung stehen, ist das Präfix "acx-" als Namespace vorhanden. –

+0

Ich verstehe. Danke Anthony und Corey. – user169867

4

Hier ist eine Vorlage, die, mit denen ich zu experimentieren, wenn komplexere Widget Plug-ins Gebäude:

(function($){ 

    // configuration, private helper functions and variables 
    var _defaultConfig = { 
     /* ... config ... */ 
     }, 
     _version = 1; 


    // the main controller constructor 
    $.myplugin = function (elm, config) { 

    // if this contructor wasn't newed, then new it... 
    if (this === window) { return new $.myplugin(elm, config || {}); } 

    // store the basics 
    this.item = $(elm); 
    this.config = new $.myplugin.config(config); 

    // don't rerun the plugin if it is already present 
    if (this.item.data('myplugin')) { return; } 

    // register this controlset with the element 
    this.item.data('myplugin', this); 

    // ... more init ... 

    }; 
    $.myplugin.version = _version; 
    $.myplugin.config = function (c) { $.extend(this, $.myplugin.config, c); }; 
    $.myplugin.config.prototype = _defaultConfig; 
    $.myplugin.prototype = { 

    /* ... "public" methods ... */ 

    }; 

    // expose as a selector plugin 
    $.fn.myplugin = function (config) { 
    return this.each(function(){ 
     new $.myplugin(this, config); 
    }); 
    }; 

})(jQuery); 

Ich lege die Standard-Konfiguration und Version an der Spitze, einfach weil es am wahrscheinlichsten 012 istSache, die jeder liest den Code sucht. Die meiste Zeit wollen Sie nur den Einstellungsblock untersuchen.

Dies wird „myplugin“ an zwei Stellen aus, da ein Konstruktor für die Widget-„Controller“ auf $ und als Sammelmethode auf $.fn. Wie Sie sehen können $.fn Methode tut nichts wirklich, außer neue Controller zu installieren.

Die Konfiguration ist ein prototypisch geerbtes Objekt, bei dem der Standardwert der Prototyp ist. Dies gibt erweiterte Flexibilität mit Asigining-Werte wie Sie können die "nächsten" Standardeinstellungen in $.myplugin.config zuweisen, oder ändern Sie alle laufenden Plugin-Standard mit $.myplugin.config.prototype. Dazu müssen Sie immer mit $ .extend zuweisen oder Sie werden das System brechen. Mehr Code könnte dem entgegenwirken, aber ich möchte lieber wissen, was ich mache. :-)

Die Instanz des Controllers bindet sich selbst an das Element über die data()-Methode von jQuery und testet sie tatsächlich, um zu testen, dass sie nicht zweimal auf demselben Element ausgeführt wird (obwohl Sie sie möglicherweise neu konfigurieren möchten)).

Dies gibt Ihnen die folgende Schnittstelle zur Steuerung:

// init: 
$('div#myid').myplugin(); 

// call extraMethod on the controller: 
$('div#myid').data('myplugin').extraMethod(); 

Der größte Fehler auf diesem Ansatz ist, dass es ein bisschen nervig ist es, den „dieser“ Kontext mit jedem Ereignisse Zuordnung zu halten.Bis der Kontext für Ereignisse in jQuery eintrifft, muss dies mit einer großen Anzahl von Schließungen geschehen.

Hier ist ein einfaches Beispiel dafür, wie eine (unvollständige und nutzlose) Plugin aussehen könnte:

(function($){ 

    // configuration, private helper functions and variables 
    var _defaultConfig = { 
     openOnHover: true, 
     closeButton: '<a href="#">Close</a>', 
     popup: '<div class="wrapper"></div>' 
     }, 
     _version = 1; 

    // the main controller constructor 
    $.myplugin = function (elm, config) { 

    // if this contructor wasn't newed, then new it... 
    if (this === window) { return new $.myplugin(elm, config || {}); } 
    this.item = $(elm); 
    this.config = new $.myplugin.config(config); 
    if (this.item.data('myplugin')) { return; } 
    this.item.data('myplugin', this); 

    // register some events 
    var ev = 'click' + (this.config.openOnHover) ? ' hover' : ''; 
    this.item.bind(ev, function (e) { 
     $(this).data('myplugin').openPopup(); 
    }); 

    }; 
    $.myplugin.version = _version; 
    $.myplugin.config = function (c) { $.extend(this, $.myplugin.config, c); }; 
    $.myplugin.config.prototype = _defaultConfig; 
    $.myplugin.prototype = { 

    openPopup: function() { 
     var C = this.config; 
     this.pop = $(C.popup).insertAfter(this.item); 
     this.pop.text('This says nothing'); 
     var self = this; 
     $(C.closeButton) 
      .appendTo(pop) 
      .bind('click', function() { 
      self.closePopup(); // closure keeps context 
      return false; 
      }); 
     return this; // chaining 
    }, 

    closePopup: function() { 
     this.pop.remove(); 
     this.pop = null; 
     return this; // chaining 
    } 

    }; 

    // expose as a selector plugin 
    $.fn.myplugin = function (config) { 
    return this.each(function(){ 
     new $.myplugin(this, config); 
    }); 
    }; 

})(jQuery); 
0

Instanz Manipulation ! Das ist was du willst, oder? Gute alte Mode, Echtzeit-Instanzmanipulation. Das wollte ich auch. Ich googelte die gleiche Frage und konnte nirgends eine gute Antwort bekommen (wie die oben genannten), also habe ich es herausgefunden. Ich mag meine Lösung nicht, weil es wie eine Runde um Zugang zu Instanzmethoden und seltsam für eine Jquery-Verbraucher scheint, aber jQuery ist in erster Linie komisch, aber schön. Ich ein einfaches Plugin schrieb Bilder zu verblassen, aber dann, wenn ich mit ihm mehr tun musste, wollte ich hier, um dieses Ergebnis eine Live-Instanz belichten Methoden zu bekommen ->example, habe ich folgende:

var instanceAccessor = {}; 
var pluginOptions = {'accessor':instanceAccessor} 
$('div').myPlugin(pluginOptions); 

Dann Innerhalb des Plugins füge ich Methoden zu diesem übergebenen Objekt 'Accessor' hinzu, da es ein Objekt ist. Ich setzen die Methoden innerhalb des Plugin wie folgt aus:

if (pluginOptions.accessor != null && typeof(pluginOptions.accessor) === 'object') { 
    pluginOptions.accessor.exposedMethod = function (someParam) { 
    // call some private function here and access private data here 
    }; 
} 

Dann wird der Verbraucher dieses Plugins die Instanzmethode oder Methoden jederzeit während der Laufzeit aufrufen können, wie wir vor jquery zu tun verwendet machte dieses seltsam:

instanceAccessor.exposedMethod('somevalue'); 

Sie können nach "dumb cross fade" auf jquery plugin suchen, um mein dumm plugin zu finden und den Code für sich selbst zu sehen.

1

Hier ist mein nehmen auf sie:

Ich habe ein Objekt innerhalb des Verschlusses, der verwendet wird Instanz-Objekte zu erstellen. Die Instanzobjekte werden mithilfe der jQuery-Methode data() an den Elementknoten angehängt. Diese Instanzobjekte verfügen über öffentliche Methoden, die Sie bei Bedarf aufrufen können.

(function($) 
{  
// This is used to create AutoComplete object that are attatched to each element that is matched 
// when the plugin is invoked 
var AutoCompleteEx = function(options, acx) { 

    // PRIVATE VARIABLES 
    var timerID; 
    var input; 

    //Give Div Correct Class & Add <ul> w/ input item to it 
    acx.addClass("autoCompleteEx"); 
    acx.html("<ul><li class=\"input\"><input type=\"text\"/></li></ul>"); 

    //Grab Input As JQ Object 
    input = $("input", acx); 

    //Wireup Div 
    acx.click(function() 
    { 
     input.focus().val(input.val()); 
    }); 


    //Wireup Input 
    input.keydown(function(e) 
    { 
     var kc = e.keyCode; 
     if(kc == 13) //Enter 
     { 

     } 
     else if(kc == 27) //Esc 
     { 

     } 
     else 
     { 
      //Resize TextArea To Input 
      var width = 50 + (_txtArea.val().length*10); 
      _txtArea.css("width", width+"px");  
     } 
    }); 

    // PUBLIC METHODS 

    this.setTimerID = function(id) { 
    timerID = id; 
    }; 

    this.getTimerID = function() { 
    return timerID; 
    }; 

}; 


//Attach this new method to jQuery 
$.fn.autoCompleteEx = function(options) 
{  
    //Merge Given Options W/ Defaults, But Don't Alter Either 
    var opts = $.extend({}, $.fn.autoCompleteEx.defaults, options); 

    //Iterate over the current set of matched elements 
    return this.each(function() 
    { 
     var acx = $(this); //Get JQuery Version Of Element (Should Be Div) 

     // creating a new AutoCompleteEx object and attach to the element's data, if not already attached 
     if (!acx.data('autoCompleteEx')) { 
      acx.data('autoCompleteEx', new AutoCompleteEx(options, acx)); 
     } 

    }); //End Each JQ Element 

}; //End autoCompleteEx() 

//Default Settings 
$.fn.autoCompleteEx.defaults = 
{ 
    minChars: 2, 
    delay:  300, 
    maxItems: 1 
}; 

//End Of Closure 
})(jQuery); 

Sie können die Methoden wie folgt aufrufen:

$("div#someDiv").autoCompleteEx(); 
$("div#someDiv").data('autoCompleteEx').setTimerID(123); 
var timerId = $("div").data('autoCompleteEx').getTimerID(); 
console.log(timerId); // outputs '123' 

Und wenn Sie mehr als eine sind Instanziierung:

$("div.someDiv").autoCompleteEx(); 
$("div.someDiv").eq(0).data('autoCompleteEx').setTimerID(123); 
$("div.someDiv").eq(1).data('autoCompleteEx').setTimerID(124); 
var firstTimerId = $("div").eq(0).data('autoCompleteEx').getTimerID(); 
var secondTimerId = $("div").eq(1).data('autoCompleteEx').getTimerID(); 
console.log(firstTimerId); // outputs '123' 
console.log(secondTimerId); // outputs '124' 
Verwandte Themen