Здесь я постарался описать основные моменты, если что-то забыл, то спрашивайте.
Сам код плагина:
(function($, window, undefined) {
'use strict';
/* Общие настройки плагина */
var plugin = {
name: 'plugin',
version: '1.0.0',
data: {
setting: 'setting',
general: 'general'
}
};
/* Настройки инициализации по умолчанию */
var defaults = {
color: 'red',
background: 'black',
padding: '10px'
};
var methods = {};
methods.init = function($this, options, common) {
/**
* Записываем настройки плагина в $.data элемента,
* чтобы потом в любой момент достать настройки
**/
var setting = function() {
var params = $.extend(true, {}, defaults, options);
$this.data(plugin.data.setting, params);
return params;
}();
/**
* Создаем общий объект свойств, которыми будем пользоватся
* в методе init. Общий объект заменяет глобальные переменные в методе init,
* так удобней и чище, все в одном месте. Не нужно на этом уровне создавать
* var flag = true; и использовать его по всему коду init и в функциях замыкания,
* лучше объект
**/
var general = function() {
var params = $.extend(true, {}, {
time: Date.now(),
context: $this.get(0)
}, common);
$this.data(plugin.data.general, params);
return params;
}();
/* Начало инициализации плагина */
$this.css({
color: setting.color,
background: setting.background
});
setPadding();
/* Конец инициализации плагина */
/* Функции в замыкании для видимости: $this, setting, general */
function setPadding() {
general.context.style.padding = setting.padding;
}
};
/**
* Метод SET. Логика его в том, чтобы взять текущие настройки
* плагина из $.data элемента, присоеденить свои
* и переинициализировать плагин уже с новыми настройками
**/
methods.set = function(key, value) {
var setting = $(this).data(plugin.data.setting);
switch (typeof key) {
case 'string':
if (key.includes('.')) {
nestedObjectPath(setting, key, value);
} else {
setting[key] = value;
}
break;
case 'object':
setting = $.extend(true, {}, setting, key);
break;
}
return methods.init($(this), setting, {
type: 'update',
method: 'set'
});
};
methods.get = function(category, key) {
var section = $(this).data(category);
if (key) {
if (key.includes('.')) {
return nestedObjectPath(section, key);
} else {
return Object.getOwnPropertyDescriptor(section, key).value;
}
}
return section;
};
methods.destroy = function() {
$(this).removeData(plugin.data.setting).fadeOut(200, function() {
$(this).empty().show();
});
};
methods.version = function() {
return plugin.version;
};
/* Все остальные общие функции, которым не нужна область видимости init метода */
/**
* Получить/установить значение объекта передав путь строкой ('price.current.USD')
* @param {object} object - объект
* @param {string} key - путь к свойству
* @param {any} value - значение
* @returns {any} - значение свойства объекта
**/
function nestedObjectPath(object, key, value) {
var path = key.split('.');
var get = function(path, object) {
return path.reduce(function(previous, current) {
return previous[current];
}, object);
};
if (value) {
var way = path.pop();
get(path, object)[way] = value;
return object;
} else {
return get(path, object);
}
}
/* Конец объявления общих функций */
/* Инициализации плагина и запуск методов */
$.fn[plugin.name] = function(setting) {
if (typeof setting === 'object' || !setting) {
return $.each(this, function() {
methods.init($(this), setting, {
type: 'init',
method: 'init'
});
});
} else if (typeof setting === 'string') {
var params = Array.prototype.slice.call(arguments, 1);
var context = this.get(0);
switch(setting.toLowerCase()) {
case 'set':
return methods.set.apply(context, params);
case 'get':
return methods.get.apply(context, params);
case 'destroy':
return methods.destroy.call(context);
case 'version':
return methods.version();
}
}
};
})(jQuery, window);
Использование плагина, методы:
/* Инициализация плагина с параметрами по умолчанию */
$('div').plugin();
/* Инициализация плагина с параметрами */
$('div').plugin({
color: 'green',
background: 'white'
});
/* Изменим параметры плагина, например по клику кнопке */
$('button').on('click', function() {
$('div').plugin('set', 'color', 'yellow');
});
/* Или передадим больше параметров для изменения */
$('button').on('click', function() {
$('div').plugin('set', {
color: 'black',
background: 'white'
});
});
/**
* Если у нас в настройках вложенные объекты
* то для этого мы объявили функцию nestedObjectPath
* и описали логику в методах set и get
* У нас появилась возможность одной строкой
* имзенить/получить свойства вложеных объектов
**/
$('div').plugin('set', 'color.theme.light', 'white');
/* Или передадим объектом */
$('div').plugin('set', {
color: {
theme: {
light: 'white'
}
}
});
/* Получить настройки/параметры плагина */
var color = $('div').plugin('get', 'setting', 'color');
/* Или получим general объект */
var time = $('div').plugin('get', 'general', 'time');
/**
* Отвяжем/разрушим плагин.
* Этот метод индивидуальный для каждого плагина
* и данный пример не является универсальным для всех плагинов
**/
$('div').pluign('destroy');
/* Получить текущюю версию плагина */
$().plugin('version');
Поповоду ошибок в вашем плагине:
Никогда так не делайте, вставка в DOM должна быть только одна:
item.append(inputFile).append(inputText).append(preview);
this.append(item);