На одном из сайтов, который я имею честь обслуживать, для кастомизации селекта используется замечательный jQuery-плагин cuSel. Он удобен тем, что достаточно прост в настройке и позволяет кастомизировать даже полосу прокрутки.
Но иногда случается так, что список элементов может быть очень большим. И быстро найти нужный пункт не так просто.
Однажды мне поступила задача реализовать возможность ввода текста и фильтрации элементов по первым буквам. Список состоял из названий городов Украины и был достаточно длинным. Поскольку в самом плагине данная возможность отсутствовала, а отказываться от красивого селекта как и я так и заказчик не хотел, было принято решение внести небольшие доработки в код скрипта.
Сегодня я постараюсь повторить все это вместе с вами. Для этого возьмем демонстрационный пример со странички плагина. В архиве содержаться все необходимые библиотеки и стили. На странице index.html автор подготовил несколько примеров подключения и использования плагина. Давайте добавим фильтрацию для первого селекта, в котором содержится список стран.
Для ввода текста мы будем использовать прозрачное текстовое поле, которое по клику будет налаживаться верхним слоем на селект. Добавим для этого поля соответствующий css-класс в файл css/cusel.css и установим такие же размеры для блока, в котором отображается текст выбранного элемента списка.
.cusel .search-field { position: absolute; outline:0; border: 0; background: transparent; display:none; } .cusel .search-field, .cuselText { width: 144px; height: 20px; line-height:20px; padding: 3px 30px 3px 6px; }
Для того чтобы была возможность добавлять фильтрацию только нужным селектам, будем помечать их дополнительным классом filtering.
<select class="sel80 filtering" id="country" name="country" tabindex="2">
Откроем файл js/cusel.js и добавим следующий код в функцию cuselEvents.
jQuery(".cusel").each(function () { var itv; var elm = $(this); if (elm.hasClass("filtering") && elm.find(".search-field").length == 0) { var f = $("<input type='text' />") f.addClass("search-field"); f.keydown(function () { clearInterval(itv); var list = elm.find(".cusel-scroll-pane > span"); itv = setInterval(function () { list.each(function () { var item = $(this); item.show(); if (item.text().toLowerCase().indexOf(f.val().toLowerCase()) != 0) item.hide(); }); var d = elm.find(".cusel-scroll-pane").eq(0).attr("id"); jQuery("#" + d)[0].scrollTo(0); clearInterval(itv); }, 100); }); f.click(function () { $(this).val('').hide(); elm.focus(); }); elm.append(f); } });
Что делает данный код? Находит на странице все элементы с классом «cusel» т.к. именно этот класс используется в стилизированных селектах. Далее, если для селекта указан класс «filtering» и он не имеет дочерний элемент с классом «search-field» (наше поле для ввода текста), то такое поле создается и на него вешается обработчик события. Обработчик, по каждому нажатию клавиш в поле, находит пункты в списке, текст которых не соответствует тексту в поле и просто скрывает их.
Теперь нам нужно сделать так, чтобы по клику на селекте над ним появлялось наше прозрачное поле. Для этого в той же функцие cuselEvents найдем обработчик события «click». В нем необходимо отыскать часть кода помеченную комментарием автора «если кликнули по самому селекту (текст)» и изменить следующим образом.
/* если кликнули по самому селекту (текст) */ if((clickedClass.indexOf("cuselText")!=-1 || clickedClass.indexOf("cuselFrameRight")!=-1) && clicked.parent().prop("class").indexOf("classDisCusel")==-1) { var cuselWrap = clicked.parent().find(".cusel-scroll-wrap").eq(0); var parent = clicked.parents(".cusel"); if (parent.hasClass("filtering")) { var txt = parent.children(".cuselText"); var sf = parent.children(".search-field"); if(sf.is(":hidden")) { txt.text(""); sf.show().focus(); } else { txt.text(parent.find(".cuselActive").eq(0).text()); sf.val("").hide(); } } /* если выпадающее меню скрыто - показываем */ cuselShowList(cuselWrap); }
Поскольку поле для ввода текста прозрачное, чтобы не перекрывать фон, мы очищаем текст выбранного элемента в селекте. Повторный клик будет возвращать исходное состояние элемента.
Теперь сделаем, чтобы при выборе элемента в списке, поле наоборот скрывалось. Ниже найдите блок помеченный комментарием автора «если выбрали позицию в списке» и добавьте туда следующий код
else if(clicked.is(".cusel-scroll-wrap span") && clickedClass.indexOf("cuselActive")==-1) { var parent = clicked.parents(".cusel"); if (parent.hasClass("filtering")) { parent.children(".search-field").val('').hide(); parent.find(".cusel-scroll-pane > span").show(); } //оригинальный код }
Как видно при этом мы делаем видимыми скрытые при фильтрации элементы списка.
Логично бы было, если пользователь кликнет все списка, закрыть список и спрятать поле фильтра. Поэтому находим ниже блок, помеченный комментарием автора «скрываем раскрытые списки, если кликнули вне списка» и изменяем его следующим образом.
/* скрываем раскрытые списки, если кликнули вне списка */ else { var wrap = jQuery(".cusel-scroll-wrap"); var parent = wrap.parents(".cusel"); parent.each(function () { var elm = $(this); if (elm.hasClass("filtering")) { elm.find(".cuselText").text(elm.find(".cuselActive").eq(0).text()); elm.find(".search-field").val('').hide(); elm.find(".cusel-scroll-pane > span").show(); } }); wrap.hide(); parent.removeClass("cuselOpen") }
И теперь последний штрих. В самом конце функции cuselEvents вы найдете кусок кода помеченный следующим комментарием
/* функция отбора по нажатым символам (от Alexey Choporov) отбор идет пока пауза между нажатиями сиволов не будет больше 0.5 сек keypress нужен для отлова символа нажатой клавиш */
Функция Алексея подбирает подходящее значение по первой букве. Мы же реализовываем возможность отбора по нескольким буквам. Поэтому во избежание конфликтов код Алексея необходимо закомментировать.
ссылка на оригинал статьи http://habrahabr.ru/post/175623/
Добавить комментарий