Помощник
Здравствуйте, гость ( Вход | Регистрация )
![]()
Сообщение
#225982
|
|
![]() Special Группа: Главные администраторы Сообщений: 13264 Спасибо сказали: 2030 раз ![]() |
Реализация метода getElementsByClassName
Что-то у меня голова идет кругом. Обычно все в голове по полочкам, а тут не могу сконцентрироваться и все перемешалось. И снова этот IE (Internet Explorer).. Ради него и некоторых других недобраузеров снова костыли.. Но нужно сделать элегантно и универсально (кроссбраузерно). Давайте напишем вместе универсальную реализацию метода getElementsByClassName (поиск элементов по классу). Сколько я не искал в сети, нет ни одной нормальной реализации. Вариантом и инфы масса, отчего и запутался в конец, хотя по сути вопрос простой. Может я и быстрее решу данный вопрос, но конспектируя данным образом условное ТЗ и свои действия, может в голове проще будет собрать все во едино. Некоторые условия функции:
querySelectorAll, getElementsByClassName, getElementsByTagName В зависимости от наличия метода в браузере, будем производить разбор селекторов по одному из них. Некоторые скажут, в принципе все решается одной строкой методом querySelectorAll, так как большинство браузеров имеют данный нативный метод. Но! Парадокс, не парадокс, а у многих на работе (и дома) используются старые ОС и главное, старые браузеры, которые пользователи просто почему-то не хотят, не могут и т.д. их обновить или установить адтернативу родному. Ну что поделать, не будем скидывать со счетов таких пользователей и наша задача их не обделить (хотя некоторые и ратуют за то, чтобы заставить пользователей обновляться, а не писать ради них лишний программный код и не лепить костыли). Но все же.. У кого есть идеи и предложения своих вариантов, выкладывайте. P.S. Библиотеку jQuery не предлагать, ее не рассматриваем. |
![]() ![]() |
|
Ответить |
![]()
Сообщение
#225985
|
|
![]() Любопытный Группа: Супермодератор Сообщений: 3331 Спасибо сказали: 1230 раз ![]() |
![]() ![]() куда там еще советовать... |
![]() ![]() |
|
![]()
Сообщение
#225986
|
|
![]() Special Группа: Главные администраторы Сообщений: 13264 Спасибо сказали: 2030 раз ![]() |
Будем приобщать!
![]() ![]() |
![]() ![]() |
|
![]()
Сообщение
#226024
|
|
![]() Special Группа: Главные администраторы Сообщений: 13264 Спасибо сказали: 2030 раз ![]() |
Итак. Пока выложу шаблон, который мы и заполним так, как поставим условия проверки.
CODE //-------------------------------------------------------------------//
// Функция поиска элементов по классу. // Никаких здесь поисков по TAG и атрибутам. Данная функция будет, // как часть метода find, в котором уже и будет выборка по типу // селекторов. // // (c) Saveliy Severniy //-------------------------------------------------------------------// ss.getElementsByClass = function(getClass,parent){ var elem = parent || document; var result = []; if( elem.querySelectorAll ) { //-------------------------------------------------------------------// // Самое оптимальное, быстрое и современное, если доступно, // используем querySelectorAll. // Возвращаем найденные элементы нативным способом браузера. // возвращает все элементы внутри elem, удовлетворяющие CSS-селектору. //-------------------------------------------------------------------// // Наш код // return result; } else if( elem.getElementsByClassName ) { //-------------------------------------------------------------------// // Если браузер не поддерживает querySelectorAll, но // поддерживает getElementsByClassName. //-------------------------------------------------------------------// // Наш код // return result; } else { //-------------------------------------------------------------------// // Ручной поиск и выборка элементов. // Ни один выше метод не поддерживается, поэтому // используем метод getElementsByTagName. //-------------------------------------------------------------------// // Наш код // return result; } }; |
![]() ![]() |
|
![]()
Сообщение
#226027
|
|
![]() Master Группа: Админ Сообщений: 3046 Спасибо сказали: 418 раз ![]() |
![]() ![]() куда там еще советовать... Не многовато пару ты назвал? ![]() Тут я думаю, сам спросил, сам ответил!!! ![]() |
![]() ![]() |
|
![]()
Сообщение
#226028
|
|
![]() Любопытный Группа: Супермодератор Сообщений: 3331 Спасибо сказали: 1230 раз ![]() |
Не.. с вопросом всё понятно. Но Саве не нужна стандартная библиотека. Хочет сам написать функцию под свои потребности.
А для этого нужен чел с каждодневным опытом работе в java. А мы тут каждый день пытаемся прокормить семью |
![]() ![]() |
|
![]()
Сообщение
#226105
|
|
![]() Special Группа: Главные администраторы Сообщений: 13264 Спасибо сказали: 2030 раз ![]() |
Реализация метода getElementsByClassName()
Наш новый метод под именем getElementsByClassNameEmulNative() Сколько не рылся в сети, нигде не смог найти корректную реализацию метода getElementsByClassName(). Вариантов масса, но все они обладают одним недостатком, ни в одной реализации никто не предложил вариант поиска по нескольким классам одновременно. Поиск срабатывал только по одному указанному классу, либо по всем, например указано два класса, но будут найдены все элементы, которые содержат один из классов, то есть по принципу логического ИЛИ (OR) и отсутствие логического И (AND). Это ошибка. По спецификации на данный метод все наоборот. Нет логического ИЛИ, есть только И, то есть если указано два класса, то должны быть выбраны только те элементы, которые содержат эти два класса и никак иначе. Много встречал вопросов людей, которые ищут реализацию метода getElementsByClassName() аналогично нативному (родному) методу. Для чего нужна такая реализация? Да просто не во всех браузерах есть данный метод, а использую данную реализацию, можно не переживать за тип используемого браузера. Выкладываю решение, которое полностью соответствует нативному методу. Конечно это не решение задачи, поставленной в оглавлении темы, это будет только эпизод из будущего решения. Ведь данный метод хоть и кроссбраузерный, но он в оригинальном исполнении на мой взгляд не обладает польностью нужной логической функциональностью, например отсутсвует поиск по логическому ИЛИ. Конечно я мог бы сюда добавить и логическое ИЛИ, и реализацию querySelectorAll(), но тогда бы мы ушли от спецификации по данному методу. Поэтому просто была создана функция, которая полностью реализует то, что было заложено по спецификации. А более удобное, универсальное и доработанное решение будет позже. Хотя честно сказать, в 95% случаев большинство кодеров используют поиск элементов всего по одному классу, но это как правило не в больших проектах. Ну раз народ искал данный вариант реализации, пожалуйста.. P.S. Встречал часто такие варианты реализаций от умных товарищей, которые всегда ведут поиск по всему документу, без возможности сузить круг поиска, утверждая, что по спецификации данный метод ищет только по всему документу. Но это огромная лишняя нагрузка и потеря времени. Если нам надо найти элемент с нужным классом только в определенном блоке, таблице, ну зачем нам проходить тысячи элементов, сканируя весь документ?? По спецификации getElementsByClassName() может быть вызвана для любого элемента, а не только для "document"! Об этом не только сказано, как должно быть, но и реальные тесты подтверждают обратное. https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname Примеры родной функции: getElementsByClassName() ( описание метода и примеры ) Ну и обещанная реализация метода getElementsByClassName().. CODE /**
* getElementsByClassNameEmulNative() * * This method of real emulate getElementsByClassName(). * * Функция, которая полностью реализует то, что заложено по * спецификации getElementsByClassName(). * * При указании нескольких классов их разделяют пробелом. * Если указано несколько классов, будут найдены элементы по типу * логического И (AND). * * (c) Saveliy Severniy */ getElementsByClassNameEmulNative = function(getClass,parent){ var elem = parent || document; var result = []; if( !getClass ) return result; var list = elem.getElementsByTagName('*'); // Выбираем все дочерние узлы. var classArray = getClass.split(/\s+/); // Разбиваем список классов var lenClasses = classArray.length; // Сколько у нас искомых классов. var lenList = list.length; // Сколько узлов нашлось. var i,j,p; // Перебираем все дочерние узлы for(i = 0; i < lenList; i++) { p = 0; // Перебираем все классы for(j = 0; j < lenClasses; j++) { // В паттерне \b = это граница слова. if(list[i].className.search('\\b' + classArray[j] + '\\b') != -1) { p++; } } // Нашлись все указанные классы в данном элементе? if( lenClasses == p ) { result.push(list[i]); // Добавляем найденный элемент. } } return result; }; |
![]() ![]() |
|
![]()
Сообщение
#226183
|
|
![]() Special Группа: Главные администраторы Сообщений: 13264 Спасибо сказали: 2030 раз ![]() |
Улучшенная реализация метода getElementsByClassName()
Наш новый метод под именем getElementsByClassNameExt() В данном методе мы отошли от спецификации, а точнее улучшили и дополнили данный метод логическими возможностями. Теперь можно искать элементы как логическому принципу И (AND), так и логическому ИЛИ (OR), а также и группировать поиск. Дополнительно решили вопрос с дублями найденных элементов, повторов найденных элементов не будет. Ни в одном подобном решении не были корректно решены все моменты. Все протестировано, пользуйтесь. Найдете ошибки, пишите свои комментарии и советы. CODE /**
* Ищет значение в массиве. * * Если оба операнда являются объектами, то JavaScript сравнивает внутренние ссылки, * которые равны в том случае, если они ссылаются на один и тот же объект в памяти. * * @param value * @param array * @returns {Boolean} */ inArrValue = function(value, array) { var len; if( array ) { len = array.length; for(var i = 0; i < len; i++) { if(array[i] === value) return true; } } return false; }; /** * getElementsByClassNameExt(); * * Имена классов пишем без точки. * * Варианты поиска классов: * * 1. Логическое ИЛИ (OR). Группы классов указываем через запятую. * 2. Логическое И (AND). Классы указываем через пробел. * * Пример 1. Чтобы найти элемент, содержащий любой из двух классов * (class1 или class2), нужно написать так: 'class1, class2'. * * Пример 2. Чтобы найти элемент, содержащий одновременно два * класса (class1 и class2), нужно написать так: 'class1 class2'. * * Можно группировать поиск через запятую. * Пример 3. Чтобы найти элементы, содержащие класс class1 или * классы class2 и class3, нужно написать запрос так: * 'class1, class2 class3'. * * Внутри группы повторно нельзя использовать запятую. * * (c) Saveliy Severniy */ getElementsByClassNameExt = function(getClass,parent){ var elem = parent || document; var result = []; if( !getClass ) return result; // Получаем группы var groups = getClass.split(','); // Разбиваем на группы классов. var lenGroups = groups.length; // Сколько у нас будет групп. var elemAdded = []; // Избегаем дублей найденных элементов. //console.log('Нашлось групп: ' + lenGroups); // Заранее объявляем переменные перед циклом. var list = [], classArray = [], lenClasses, lenList; var g,i,j,p; // Чтобы не дергать каждый раз DOM, заранее один раз получим все элементы. list = elem.getElementsByTagName('*'); // Выбираем все дочерние узлы. lenList = list.length; // Сколько узлов нашлось. // Перебираем все группы. Логическое ИЛИ (OR). for(g = 0; g < lenGroups; g++) { classArray = groups[g].split(/\s+/); // Разбиваем список классов lenClasses = classArray.length; // Сколько у нас искомых классов. // Перебираем все дочерние узлы. for(i = 0; i < lenList; i++) { p = 0; // Перебираем все классы. Логическое И (AND). for(j = 0; j < lenClasses; j++) { // В паттерне \b = это граница слова. if(list[i].className.search('\\b' + classArray[j] + '\\b') != -1) { p++; } } // Нашлись все указанные классы в данном элементе? if( lenClasses == p ) { if( !inArrValue(i,elemAdded) ) { result.push(list[i]); // Добавляем найденный элемент в массив результатов. elemAdded.push(i); // Помечаем найденные элементы. } } } } return result; }; |
![]() ![]() |
|
![]()
Сообщение
#226520
|
|
![]() Special Группа: Главные администраторы Сообщений: 13264 Спасибо сказали: 2030 раз ![]() |
В реализации метода getElementsByClassName() внесены улучшения.
Добавлена защита от дублей найденных элементов при логическом поиске в режиме ИЛИ (OR). Новая измененная версия метода сообщением выше: Реализация метода getElementsByClassName - Сообщение №226183 |
![]() ![]() |
|
Ответить |
![]() |
|
4.9.2024, 12:04 Посл. ответ от Ilyamiass |
|
![]() |
|
3.1.2024, 5:58 Посл. ответ от Александр |
|
![]() |
|
25.7.2022, 7:21 Посл. ответ от Fedorov |
|
![]() |
|
16.3.2022, 12:28 Посл. ответ от Saveliy |
|
![]() |
|
10.5.2019, 16:43 Посл. ответ от Saveliy |
![]() |
|
4.9.2024, 12:04 Посл. ответ от Ilyamiass |
|
![]() |
|
4.9.2024, 9:29 Посл. ответ от ypiter |
|
![]() |
|
3.9.2024, 18:20 Посл. ответ от Nikol |
|
![]() |
|
2.9.2024, 15:29 Посл. ответ от Максим |
|
![]() |
|
2.9.2024, 13:08 Посл. ответ от Reanimotor |
Сейчас: 8.9.2024, 4:11 |