Хорошая практика хранения конфигурации плагина jquery в данных?

Я хочу создать плагин jQuery с конфигурацией (например, плагин myplugin). Чем вызов $(elem).myplugin(config); После этого я хочу вызвать методы из этого плагина, например $(elem).myplugin().method(), с уже сохраненной конфигурацией.

Мое предложение - вот что:

(function($) {
    $.fn.myplugin = function(options) { 
        var $this = $(this);

        var getOptions = function() {
            return $this.data('myplugin');
        };

        var initOptions = function(opt) {
            $this.data('myplugin', opt);
        };

        var setOption = function(key, value) {
            $this.data('myplugin')[key] = value;
        }

        var updateBorderWidth = function() {  
            $this.css('border-width', 
                      getOptions().borderWidth * getOptions().coeficient);
        };

        var init = function(opt) {
            initOptions(opt);
            updateBorderWidth();
        }        

        function changeBorder(width) {            
            setOption('borderWidth', width)
            updateBorderWidth();
        }

        if(options) {
            init(options);            
        }        

        return {
            changeBorder : changeBorder
        };
    }        
})(jQuery);

И использование:

 $(function() {
     var item1 = $('#test1').myplugin({ coeficient: 1, borderWidth: 1 });
     var item1 = $('#test2').myplugin({ coeficient: 2, borderWidth: 1 });

     $('#btn').click(updateBorder);     
});

function updateBorder() {
    $('#test1').myplugin().changeBorder($('#inpt').val());
    $('#test2').myplugin().changeBorder($('#inpt').val());
}

Пример: http://jsfiddle.net/inser/zQumX/4/

Мой вопрос: хорошо ли это сделать?

Может быть, это неправильный подход. Можете ли вы предложить лучшее решение?

Ответ 1

Edit:

После поиска потоков в шаблоне плагина jQuery я нашел эти шаблоны Boilerplate которые являются более универсальными и обширными проектами, чем то, что я предложил ниже. В конечном итоге то, что вы выбираете, зависит от ваших потребностей. Шаблоны Boilerplate охватывают больше случаев использования, чем мое предложение, но каждый из них имеет свои преимущества и предостережения в зависимости от требований.


Обычно плагины jQuery возвращают объект jQuery, когда значение передается им:

.wrap(html) // returns a jQuery object

или они возвращают значение, когда параметр не передается в

.width() // returns a value

.height() // also returns a value

Чтобы прочитать пример, вызывающий вызов:

$('#test1').myplugin().changeBorder($('#inpt').val());

казалось бы, любому разработчику, который использует jQuery, как если бы два отдельных плагина использовались в тандеме, первый .myplugin(), который, как предполагается, вернет объект jQuery с некоторой манерой DOM по умолчанию, выполненной на #test1, тогда за которым следует .changeBorder($('#inpt').val()), который также может возвращать объект jQuery, но в случае вашего примера вся строка не назначается переменной, поэтому любое возвращаемое значение не используется - опять-таки это выглядит как манипуляция DOM. Но ваш дизайн не соответствует стандартным соглашениям о вызовах, которые я описал, поэтому может быть некоторая путаница для всех, кто смотрит ваш код на то, что он на самом деле делает, если они не знакомы с вашим плагином.


В прошлом я рассматривал аналогичную проблему и использовал случай, который вы описываете, и мне нравится идея иметь удобное соглашение для вызова отдельных функций, связанных с плагином. Выбор полностью зависит от вас - это ваш плагин, и вам нужно будет решить, на основе того, кто его будет использовать, но способ, которым я остановился, - просто передать имя функции, и это параметры либо как отдельные .myplugin(name, parameters) или в объекте .myplugin(object).

Я обычно делаю это так:

(function($) {
    $.fn.myplugin = function(fn, o) { // both fn and o are [optional]
        return this.each(function(){ // each() allows you to keep internal data separate for each DOM object that being manipulated in case the jQuery object (from the original selector that generated this jQuery) is being referenced for later use
            var $this = $(this); // in case $this is referenced in the short cuts

            // short cut methods
            if(fn==="method1") {
                if ($this.data("method1"))  // if not initialized method invocation fails
                    $this.data("method1")() // the () invokes the method passing user options
            } else if(fn==="method2") {
                if ($this.data("method2"))
                    $this.data("method2")()
            } else if(fn==="method3") {
                if ($this.data("method3"))
                    $this.data("method3")(o) // passing the user options to the method
            } else if(fn==="destroy") {
                if ($this.data("destroy"))
                    $this.data("destroy")()
            }
            // continue with initial configuration

            var _data1,
                _data2,
                _default = { // contains all default parameters for any functions that may be called
                    param1: "value #1",
                    param2: "value #2",
                },
                _options = {
                    param1: (o===undefined) ? _default.param1 : (o.param1===undefined) ? _default.param1 : o.param1,
                    param2: (o===undefined) ? _default.param2 : (o.param2===undefined) ? _default.param2 : o.param2,

                }
                method1 = function(){
                    // do something that requires no parameters
                    return;
                },
                method2 = function(){
                    // do some other thing that requires no parameters
                    return;
                },
                method3 = function(){
                    // does something with param1
                    // _options can be reset from the user options parameter - (o) - from within any of these methods as is done above
                    return;
                },
                initialize = function(){
                    // may or may not use data1, data2, param1 and param2
                    $this
                        .data("method1", method1)
                        .data("method2", method2)
                        .data("method3", method3)
                        .data("destroy", destroy);
                },
                destroy = function(){
                    // be sure to unbind any events that were bound in initialize(), then:
                    $this
                        .removeData("method1", method1)
                        .removeData("method2", method2)
                        .removeData("method3", method3)
                        .removeData("destroy", destroy);
                }
            initialize();
        }) // end of each()
    } // end of function        
})(jQuery);

И использование:

var $test = $('#test').myplugin(false, {param1: 'first value', param2: 'second value'}); // initializes the object
$test.myplugin('method3', {param1: 'some new value', param2: 'second new value'}); // change some values (method invocation with params)

или вы можете просто сказать:

$('#test').myplugin(); // assume defaults and initialize the selector

Ответ 2

Передача параметров в javascript через атрибуты данных - отличный шаблон, поскольку он эффективно отделяет Javascript-код и серверный код. Это также не оказывает отрицательного влияния на тестируемость кода Javascript, что является побочным эффектом многих других подходов к проблеме.

Я бы сказал, что это лучший способ для серверного кода связываться с клиентским кодом в веб-приложении.