Антон Шевчук // Web-разработчик

jQuery для начинающих. Часть 8. Расширяем фильтры // JavaScript

jQuery Logo

Продолжаем заумные статьи о jQuery, сегодня поведу речь о движке Sizzle и возможности его расширения.

Материалы данной статьи включены в учебник «jQuery для начинающих». Учебник распространяется бесплатно, и сопровождается интерактивными примерами.

Sizzle — Javascript движок для поиска элементов по CSS селектору, был неразлучен с jQuery, но с некоторых пор так же распространяется как отдельная библиотека, и может использоваться в том же Dojo Toolkit, или в вашем собственном фреймворке

API для расширения фильтров

Для начала приведу пример фильтров, которые вы возможно использовали, да не заглядывали внутрь:

$("div:animated"); // поиск анимированных элементов
$("div:hidden"); // поиск скрытых элементов div
$("div:visible"); // поиск видимых элементов div (противоположен предыдущему)

Почему я привел только эти фильтры? Всё просто — только они не входят в Sizzle, и относятся лишь к jQuery, именно такие плагины мы будем тренироваться разрабатывать. Начнем с кода, который нам поможет разобраться с API:

(function($, window, undefined){
    $.extend($.expr[':'], {
        /**
         * @param element DOM элемент
         * @param i порядковый номер элемента
         * @param match объект матчинга регулярного выражения (ищите PSEUDO в сорцах)
         * @param elements массив всех найденных DOM элементов
         */
        test: function(element, i, match, elements) {
            return true; // элемент подходит нам
            return false; // или нет
        }
    })
})(jQuery, window);

Приведенный код конечно не очень наглядный, поэтому расширю его рабочими примерами:

test: function(element, i, match, elements) {
    // мы можем создавать проверки на основе правил, которые относятся к DOM элементу
    // нам нужны лишь параграфы - $("p:test")
    if (element.tagName.toUpperCase() != 'P') return false;

    // ищем по порядковому номеру
    // $("p:test(4)")
    if (parseInt(match[3]) == (i+1)) {
        return true;
    } else
    // чёт / нечет
    // $("p:test(even)") или $("p:test(odd)")
    if (match[3] == "even" && (i%2==0)) {
        return true;
    } else if (match[3] == "odd" && (i%2==1)) {
        return true;
    } else
    // первый/последний
    // $("p:test(first)") или $("p:test(last)")
    if (match[3] == "first" && (i==0)) {
        return true;
    } else if (match[3] == "last" && (i==(elements.length-1))) {
        return true;
    }
    return false;
}

Примеры использования:

$("p:test");
$("p:test(2)");

// чёт/нечет
$("p:test(odd)");
$("p:test(even)");

// первый/последний
$("p:test(first)");
$("p:test(last)");

Вот таким не хитрым способом можно расширять фильтры, если у вас есть еще примеры возможных плагинов, прошу — комментируйте.

Пример plugin’а

Ну от тривиальных абстрактных задач к чему-то более конкретному — есть несложная задачка: «выделить ссылки в тексте в зависимости от типа: внешняя, внутренняя, якорь», ну и пример текста:

<p>
<a name="p1">Lorem ipsum dolor sit amet</a>, consectetur adipiscing elit. Ut lacinia quam
nec enim scelerisque porta. In ut lorem ipsum. Proin iaculis viverra rutrum. Maecenas quis
ante enim. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia
Curae; Vestibulum luctus tristique feugiat. Morbi dictum est dolor,
<a href="http://anton.shevchuk.name">at condimentum nisl</a>. Ut id nunc augue, at luctus
enim. Phasellus urna nunc, aliquam sit amet rutrum ac, imperdiet in nunc. Cras mattis massa
et est sodales ac auctor mi sagittis. Fusce elementum ultrices nunc, eu scelerisque massa
sodales quis. Aliquam bibendum accumsan nibh ut blandit.
</p>
<p>
<a href="index.html">Praesent venenatis dictum ante</a>, ...
</p>
<p>
Aliquam erat volutpat. ... <a href="http://google.com">Curabitur congue enim</a> ... <a href="#p1">Duis lectus tellus</a>, gravida non commodo eu, dictum a tellus. Praesent a nibh vel nisl sodales tincidunt at ac leo.
</p>

Для решения лучше всего подошли бы фильтры для селекторов:

$("a:internal");
$("a:anchor");
$("a:external");

Поскольку из коробки данный функционал не доступен, мы напишем его сами, для этого нам понадобится не так уж и много:

$.extend($.expr[':'], {
    /**
     * Пример определения внешней ссылки
     * остальные фильтры найдете на странице примеров
     * 
     * @param element нам понадобится лишь DOM Element
     */
    external: function(element) {
        // у нас ссылка?
        if (element.tagName.toUpperCase() != 'A') return false;
        // есть ли атрибут href
        if (element.getAttribute('href')) {
            // отсекаем ненужное
            if ((element.getAttribute('href').indexOf('/') === 0)             // внутренняя ссылка
                || (element.getAttribute('href').indexOf('#') === 0)        // якорь
                || (element.getAttribute('href').indexOf(window.location.hostname) === 7) // наш домен по http://...
                || (element.getAttribute('href').indexOf(window.location.hostname) === 8) // наш домен по https://...
                    ) {
                return false;
            } else {
                // да, мы нашли правильные ссылки
                return true;
            }
        } else {
            return false;
        }
    }
})

Как вы могли заметить в статье я всегда, нет не так — ВСЕГДА использую фильтр вместе с HTML тэгом который я ищу — $(“tag:filter”). Это один из пунктов оптимизации работы с фильтрами jQuery, иначе ваш фильтр будет обрабатывать все DOM элементы на странице, а это может очень сильно сказаться на производительности. Если же у вас несколько тегов, то пишите так — $(“tag1:filter, tag2:filter, tag3:filter”)

Материалы

Тут всё грустно — нашел лишь скудную официальную документацию, если есть чем поделиться, ну вы поняли…

Цикл статей

  1. jQuery для начинающих
  2. jQuery для начинающих. Часть 2. JavaScript Меню
  3. jQuery для начинающих. Часть 3. AJAX
  4. jQuery для начинающих. Часть 4. Селекторы
  5. jQuery для начинающих. Часть 5. Эффекты
  6. jQuery для начинающих. Часть 6. События
  7. jQuery для начинающих. Часть 7. Пишем плагины
  8. jQuery для начинающих. Часть 8. Расширяем фильтры
  9. jQuery для начинающих. Часть 9. Пишем плагины анимации

© Антон Шевчук 2007-2016