Оформляем красиво тег SELECT при помощи jQuery
В данной статье мы рассмотрим создание плагина jQuery, суть которого в замещение элемента
select
красиво оформленным неупорядоченным списком (ul
).
Одним из важнейших способов эффективной организации jQuery кода служит превращение его частей в плагины. Такие превращения несут в себя ряд преимуществ: код становится проще модифицировать и сопровождать, руководство повторяющими задачами упрощается. Также увеличивается скорость разработки, так как организация плагина способствует повторному использованию кода.
Поэтому мы и продемонстрируем сегодня процесс конвертирования кода в плагин. Код мы возьмем из этого руководства jQuery& CSS3 замещаем элемент select и превратим его в готовый к использованию jQuery плагин.
Основная идея

Написать jQuery плагин совсем не сложно. Для этого нужно расширить объект $.fn
своей собственной функцией. Гораздо сложнее должным образом структурировать свой код, чтобы плагин можно было легко вставить и использовать (без зависимостей).
Вот, несколько проблем, которые нам надо решить при конвертировании кода руководства в jQuery плагин:
1. Пользователю нужно дать возможность решать, какая разметка будет генерироваться для dropdown (выпадающего списка). К примеру, код руководства сильно зависит от наличия data-
атрибутов, которые содержат разметку HTML. Это слишком специфично, чтобы подключать в плагин, поэтому данную реализацию нужно исключить.
2. Из-за способа вызова плагина код нужно переписать, чтобы он использовал объект this
, который передается плагину, вместо жестко заданного селектора. Это также позволяет конвертировать не один, а несколько элементов select одновременно;
3. Код JavaScript и CSS нужно поместить в разные файлы, чтобы их было проще подключать и редактировать.
Код
Как вы помните из руководства, наш jQuery код сканирует элементы option тега select
и создает неупорядоченный список. Одновременно с этим он также ищет ряд data-
атрибутов в тегах option
, которые содержат URL на изображение и описание для использования в элементах списка.
Это слишком специфично для плагина. Пользователям нужно дать возможность переписать эту функциональность. Для решения этой проблемы можно позволить пользователям передавать плагину функцию в качестве параметра, которая и будет генерировать разметку. Если такой параметр не передается, будем обращаться к тому, который стоит по умолчанию, и который просто берет текст элемента option
и превращает его в пункт списка.
Превратим вышесказанное в код:
JQuery
(function($){
$.fn.tzSelect = function(options){
options = $.extend({
render : function(option){
return $('<li>',{
html : option.text()
});
},
className : ''
},options);
// More code will be added here.
}
})(jQuery);
Функция render
берет элемент option
(который находится в select
) и возвращает элемент li
, который подключается плагином к выпадающему списку. Это решает описанную выше проблему № 1.
Прежде чем обратиться к проблеме № 2, давайте посмотрим, как плагин будет вызываться:
JQuery
$(document).ready(function(){ $('select').tzSelect(); });
В приведенном выше коде вы можете видеть, что плагин применяется к каждому элементу select
. Получить доступ к этим элементам можно при помощи объекта this
, который передается плагину.
JQuery
return this.each(function(){
// ключевое слово "this" это текущий элемент select
var select = $(this);
// selectBoxContainer - блок обертка для ul
var selectBoxContainer = $('<div>',{
width : select.outerWidth(),
className : 'tzSelect',
html : '<div class="selectBox"></div>'
});
// dropDown - выпадающее меню
var dropDown = $('<ul>',{className:'dropDown'});
var selectBox = selectBoxContainer.find('.selectBox');
// Цикл по тегам option оригинального тега select
if(options.className){
dropDown.addClass(options.className);
}
select.find('option').each(function(i){
var option = $(this);
if(i==select.attr('selectedIndex')){
selectBox.html(option.text());
}
// Так как у нас jQuery 1.4.3 то получить доступ к атрибуту
// HTML5 data можно при помощи метода data())
if(option.data('skip')){
return true;
}
// создаем выпадающий список, согласно атрибутам HTML5
// data-icon и data-html-text
var li = options.render(option);
li.click(function(){
selectBox.html(option.text());
dropDown.trigger('hide');
// При клике отражаем изменения на оригинальное
// элементе select
select.val(option.val());
return false;
});
dropDown.append(li);
});
selectBoxContainer.append(dropDown.hide());
select.hide().after(selectBoxContainer);
// Связываем события show и hide
// с выпадающим меню dropDown:
dropDown.bind('show',function(){
if(dropDown.is(':animated')){
return false;
}
selectBox.addClass('expanded');
dropDown.slideDown();
}).bind('hide',function(){
if(dropDown.is(':animated')){
return false;
}
selectBox.removeClass('expanded');
dropDown.slideUp();
}).bind('toggle',function(){
if(selectBox.hasClass('expanded')){
dropDown.trigger('hide');
}
else dropDown.trigger('show');
});
selectBox.click(function(){
dropDown.trigger('toggle');
return false;
});
// Если произошел клик где-нибудь на странице при
// открытом выпадающем списке, то скрываем его:
$(document).click(function(){
dropDown.trigger('hide');
});
});
Показанный выше фрагмент почти идентичен коду руководства, который мы сегодня конвертируем. Единственное заметное отличие – мы присваиваем $(this)
переменной select
(строка5), раньше же это был $('select.makeMeFancy')
(жёстко запрограммированный селектор), что значительно сужало область действия кода.
Другое изменение – вместо непосредственного генерирования выпадающего списка (dropdown), мы вызываем функцию render, которую мы передали как параметр (строка51).
Собрав все воедино, мы получим полный исходный код плагина:
JQuery
(function($){
$.fn.tzSelect = function(options){
options = $.extend({
render : function(option){
return $('<li>',{
html : option.text()
});
},
className : ''
},options);
return this.each(function(){
// ключевое слово "this" это текущий элемент select
var select = $(this);
// selectBoxContainer - блок обертка для ul
var selectBoxContainer = $('<div>',{
width : select.outerWidth(),
className : 'tzSelect',
html : '<div class="selectBox"></div>'
});
// dropDown - выпадающее меню
var dropDown = $('<ul>',{className:'dropDown'});
var selectBox = selectBoxContainer.find('.selectBox');
// Цикл по тегам option оригинального тега select
if(options.className){
dropDown.addClass(options.className);
}
select.find('option').each(function(i){
var option = $(this);
if(i==select.attr('selectedIndex')){
selectBox.html(option.text());
}
// Так как у нас jQuery 1.4.3 то получить доступ к атрибуту
// HTML5 data можно при помощи метода data())
if(option.data('skip')){
return true;
}
// создаем выпадающий список, согласно атрибутам HTML5
// data-icon и data-html-text
var li = options.render(option);
li.click(function(){
selectBox.html(option.text());
dropDown.trigger('hide');
// При клике отражаем изменения на оригинальное
// элементе select
select.val(option.val());
return false;
});
dropDown.append(li);
});
selectBoxContainer.append(dropDown.hide());
select.hide().after(selectBoxContainer);
// Связываем события show и hide
// с выпадающим меню dropDown:
dropDown.bind('show',function(){
if(dropDown.is(':animated')){
return false;
}
selectBox.addClass('expanded');
dropDown.slideDown();
}).bind('hide',function(){
if(dropDown.is(':animated')){
return false;
}
selectBox.removeClass('expanded');
dropDown.slideUp();
}).bind('toggle',function(){
if(selectBox.hasClass('expanded')){
dropDown.trigger('hide');
}
else dropDown.trigger('show');
});
selectBox.click(function(){
dropDown.trigger('toggle');
return false;
});
// Если произошел клик где-нибудь на странице при
// открытом выпадающем списке, то скрываем его:
$(document).click(function(){
dropDown.trigger('hide');
});
});
}
})(jQuery);
Проблему № 3 решаем, поместив этот плагин в отдельный файл. Однако, как я упоминал ранее, мы сознательно не включили код, который содержит data-
атрибуты, чтобы сделать плагин более мобильным. Чтобы компенсировать это, нужно при вызове плагина передавать пользовательскую функцию render
, как вы можете увидеть ниже (этот код также используется в демо).
JQuery
$(document).ready(function(){
$('select.makeMeFancy').tzSelect({
render : function(option){
return $('<li>',{
html: '<img src="'+option.data('icon')+'" /><span>'+
option.data('html-text')+'</span>'
});
},
className : 'hasDetails'
});
// вызываем версию по умолчанию
$('select.regularSelect').tzSelect();
});
Вы можете использовать этот плагин, бросив папку tzSelect в корневую директорию и включив jquery.tzSelect.css и jquery.tzSelect.js в свои HTML документы.
Источник
Комментарии к статье
демка понравилась, попробую себе поставить