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

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. Пишем плагины анимации

16 thoughts on “jQuery для начинающих. Часть 8. Расширяем фильтры”

      1. последний елемент в списке. Так же и first.
        (выше пример кода, думал коммент лишний)

      2. Имеется ввиду, что в примере есть код который дублирует функционал самого Sizzle?

  1. Отличная статья =) Спасибо…

    з.ы: комменты выше можно удалить, я что то не так понял :) сначала

  2. Отличная статья. Однако было бы неплохо указать ссылку на официальную документацию.

  3. Это значит Sizle надо дописать, чтобы не надобыло каждый раз тег чекать.

    Ибо это странно, что если я пишу

    bla:stuff, мне все теги приходят, а не только bla.

    Патчик надо на эту тему в JQ отправить.

    1. В таком виде придут лишь bla, а вот если написать :stuff – то будут обрабатываться все элементы DOMa.

  4. как выбрать чекбокс там где value = Черный ?????

    var input = $(“____???????____”).parent().css({background:”yellow”, border:”1px red solid” , margin: “5px”});

  5. почему для $(“a:internal”) не написать просто $(“a[href^=’http://’]”),
    для $(“a:anchor”) – $(“a[href^=’#’]”), а для $(“a:external”) – $(“a[href^=’/’]”)? а не изобретать по сути велосипед? или я ошибаюсь?

    1. Статья о том, как разрабатывать фильтры к jQuery, было бы странно увидеть тут более сложные примеры

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.