jQuery ajax-плагин выпадающего дерева (нужна критика и советы)
Всем привет. Представляю вашему вниманию свой первый jQuery плагин (Демо) и хочу получить конструктивную критику и советы от гуру.
Суть заключается в следующем: пользователь выбирает из выпадающего списка услугу (в нашем случае взял услуги салонов красоты), которая может являться родительской для других услуг. При клике на услугу в случае если она всё-таки является родительской для списка - аяксом подгружается этот список услуг. И так до тех пор, пока скрипт не возвратит пустой массив. (function($) { function isEmpty(obj) { for (var key in obj) { return false; // если цикл хоть раз сработал, то объект не пустой => false } // дошли до этой строки - значит цикл не нашёл ни одного свойства => true return true; } var defaults = { 'url' : '/', 'title' : '{ title : заголовок }', 'name' : '{ name : заголовок }' }; var methods = { init : function(params) { var $this = $(this); // актуальные настройки, будут индивидуальными при каждом запуске var options = $.extend({}, defaults, params); // инициализируем один раз var init = $(this).data('dropdown'); if (init) { return this; } else { $(this).data('dropdown', true); //Украсили всё $(this).addClass('dropdown'); $("<a/>", { 'text' : options.title, 'name' : options.name, 'class' : 'das' }).appendTo($(this)); //Добавили UL и заполнили нулевым уровнем $("<ul/>").appendTo($(this)); $this.dropdown('getData', 0, options.url); //Показать/скрыть выпадающий список $(this).on("click", "a", function() { //Показали список $this.dropdown('toggle'); }); //Клик по пункту меню $(this).on('click', 'li', function() { $this.dropdown('getData', $(this).data('id'), options.url); if ($(this).data('id') == 0) { var text = options.title; } else { var text = $(this).text(); } $this.find("a").text(text).attr('data-id', $(this).data('id')); }); return this; } }, toggle : function() { $(this).find("ul").toggle(); }, hide : function() { $(this).find("ul").hide(); }, getData : function(id, url) { var $this = $(this); $.ajax({ type : 'POST', dataType : 'JSON', url : url, data : { id : id } }).done(function(data) { if (isEmpty(data)) { return $this.dropdown('hide'); } $this.find("ul").html(''); if (id != 0) $this.find("ul").append("<li data-id='0' class='red'>← назад</li>"); $.each(data, function(key, val) { $("<li/>", { 'data-id' : key, text : val }).appendTo($this.find("ul")) }); return this; }).fail(function(jqXHR, textStatus) { $.error("Ошибка загрузки: " + textStatus); }); } }; $.fn.dropdown = function(method) { if (this.length > 1) { $.error('Плагин можно применить только к одному элементу!'); return this; } if (methods[method]) { // если запрашиваемый метод существует, мы его вызываем // все параметры, кроме имени метода прийдут в метод // this так же перекочует в метод return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); } else if ( typeof method === 'object' || !method) { // если первым параметром идет объект, либо совсем пусто // выполняем метод init return methods.init.apply(this, arguments); } else { // если ничего не получилось $.error('Метод "' + method + '" не найден в плагине jQuery.dropdown'); } }; })(jQuery); Вызов плагина: $("#service").dropdown({ 'url' : '/php/service.php', //JSON массив для текущего уровня 'title' : 'выбрать услугу', 'name' : 'service' }); Логика работы PHP-скрипта который подтягивает из базы и возвращает JSON для текущего уровня: if (isset($_POST['id'])) { $parent_id = $_POST['id']; } else { $parent_id = 0; } $query = "SELECT * FROM services WHERE parent_id = $parent_id"; $res = mysql_query($query) or die(mysql_error()); $num = mysql_num_rows($res); while ($row = mysql_fetch_array($res)) { $result[$row['id']] = $row['name']; } if($result == NULL) $result = array(); echo json_encode($result); mysql_close(); Демо Также остался ряд вопросов по реализации: 1. сейчас скрытие выпадающего меню происходит именно по клику на ссылку, а логичнее было бы сделать чтобы скрывалось при клике на любую часть страницы кроме .dropdown. Пробовал делать так: $(document).on('click', function(){ $this.dropdown('hide'); });но он срабатывает первым независимо от того, в какой части вставить этот кусок и попросту не открывается выпадающее окно. 2. при выборе последнего уровня PHP-скрипт возвращает [] и мы скрываем наш блок. По хорошему нужно в наш <ul/> после скрытия подгрузить список с parent_id == 0, то есть выполнить $this.dropdown('getData', 0, options.url); Но options.url лежит в другой области видимости и недоступен в методе getData. По идее можно передать его как параметр в этот метод, но код будет дублироваться. Можно ли как то options после инициализации сделать глобальным в пределах нашего плагина и иметь доступ к нему из всех методов плагина? |
Часовой пояс GMT +3, время: 18:44. |