Статьи

Пользовательские события и API специальных событий в jQuery

Веб-страницы, по большей части, ориентированы на события. В библиотеках, таких как jQuery, предусмотрены вспомогательные методы, облегчающие понимание этой функции. В этом уроке мы рассмотрим расширение этих методов для создания ваших собственных событий в пространстве имен.


Перед роскошью библиотек JavaScript, если вы хотите добавить простое событие click к элементу, вам необходимо выполнить следующие действия для поддержки всех браузеров:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
var elt = document.getElementById(«#myBtn»);
 
if(elt.addEventListener)
{
    elt.addEventListener(«click», function() {
        alert(‘button clicked’);
    });
}
else if(elt.attachEvent)
{
    elt.attachEvent(«onclick», function() {
        alert(‘button clicked’);
    });
}
else
{
    elt.onclick = function() {
        alert(‘button clicked’);
    };
}

Теперь библиотеки JavaScript поставляются с вспомогательными методами, чтобы сделать управление событиями более понятным. Например, выполнение вышеизложенного в jQuery гораздо более сжато.

1
2
3
$(«#myBtn»).click(function() {
    alert(‘button clicked’);
});

Независимо от вашей реализации, есть три основных части событий:

  • Слушатель — ждет или «слушает» событие, чтобы выстрелить.
  • Диспетчер — запускает событие для запуска.
  • Обработчик — функция, выполняемая при возникновении события.

В нашем событии click в начале урока слушатель — это событие click, ожидающее нажатия на элемент #myBtn. При щелчке по элементу #myBtn он отправляет и запускает обработчик; которая в данном случае является анонимной функцией для отображения сообщения alert ().


jQuery позволяет нам сделать еще один шаг и создать собственные события. В этом руководстве мы будем использовать неупорядоченный список списка каталогов и добавим функциональность с помощью пользовательских событий, которые будут сворачивать и расширять каталоги. Давайте начнем с нашей базовой структуры страницы, которая будет использоваться в следующих примерах.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Strict//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd»>
<html xmlns=»http://www.w3.org/1999/xhtml» xml:lang=»en» lang=»en»>
<head>
    <title>jQuery Custom Events</title>
    <meta http-equiv=»Content-Type» content=»text/html; charset=utf-8″ />
     
    <style type=»text/css»>
        body {background: #fefefe;
         
        #tree {color: #333;
            .directory {list-style-image: url(‘images/directory.png’);}
            .css {list-style-image: url(‘images/css.png’);}
            .html {list-style-image: url(‘images/html.png’);}
            .js {list-style-image: url(‘images/js.png’);}
            .gif,
            .png,
            .jpg {list-style-image: url(‘images/image.png’);}
    </style>
     
</head>
<body>
    <ul id=»tree»>
        <li>root/
            <ul>
                <li>index.html</li>
                <li>about.html</li>
                <li>gallery.html</li>
                <li>contact.html</li>
                <li>assets/
                    <ul>
                        <li>images/
                            <ul>
                                <li>logo.png</li>
                                <li>background.jpg</li>
                            </ul>
                        </li>
                        <li>js/
                            <ul>
                                <li>jquery.js</li>
                                <li>myscript.js</li>
                            </ul>
                        </li>
                        <li>css/
                            <ul>
                                <li>page.css</li>
                                <li>typography.css</li>
                            </ul>
                        </li>
                    </ul>
                </li>
            </ul>
        </li>
    </ul>
     
    <script type=»text/javascript» src=»http://google.com/jsapi»></script>
    <script type=»text/javascript»>
        google.load(«jquery», «1»);
        google.setOnLoadCallback(function() {
            $(function() {
                addIcons();
 
                 
            });
            function addIcons()
            {
                $(«#tree li»).each(function() {
                    if($(this).children(«ul»).length)
                    {
                        $(this).addClass(«directory»);
                    }
                    else
                    {
                        var txt = $(this).text();
                        var fileType = txt.substr(txt.indexOf(«.») + 1);
                        $(this).addClass(fileType);
                    }
                });
            }
        });
    </script>
</body>
</html>

Здесь мы создаем простой список каталогов, используя неупорядоченный список. Мы включили jQuery из CDN Google JSAPI и назвали addIcons (), который добавляет изображения каждого файла и папки в зависимости от указанного расширения файла. Эта функция предназначена исключительно для эстетических целей. В этом нет необходимости ни для одного из пользовательских кодов событий, которые мы собираемся реализовать. Результат этого шага и можно посмотреть здесь .


Шаг 1

Прежде чем мы начнем добавлять события в наш пример списка каталогов, нам нужно понять, как работают .bind () и .trigger (). Мы используем bind (), чтобы прикрепить событие ко всем соответствующим элементам, которые в данный момент находятся на странице. Затем используйте .trigger (), если вы хотите отправить событие. Давайте посмотрим на быстрый пример.

1
2
3
4
5
$(«#myBtn»).bind(«click», function(evt) {
    alert(‘button clicked’);
});
 
$(«#myBtn»).trigger(«click»);

В приведенном выше коде при щелчке элемента с идентификатором «myBtn» появится предупреждающее сообщение. Кроме того, наш триггер () фактически запустит событие click сразу после загрузки страницы. Просто помните, что bind () — это то, как вы прикрепляете событие. Пока .trigger (), вы заставляете событие отправляться и запускаете обработчик события.


Метод .bind () не ограничивается только событиями браузера, но может использоваться для реализации ваших собственных пользовательских событий. Давайте начнем с создания пользовательских событий с именем collapse и развернем наш пример с перечнем каталогов.

Во-первых, давайте свяжем событие свертывания со всеми каталогами, представленными в нашем неупорядоченном списке.

1
$(«#tree li:parent»).bind(«collapse», function(evt) {

Здесь мы находим все элементы, которые являются родителями, и передаем сжатие имени события в метод .bind (). Мы также назвали первый параметр evt , который представляет объект события jQuery.

1
$(evt.target).children().slideUp().end().addClass(«collapsed»);

Теперь мы выбираем цель мероприятия и перемещаем всех его детей. Кроме того, у нас был свернут класс CSS к нашему элементу каталога.

1
}).bind(«expand», function(evt) {

Мы присоединяемся к событиям и присоединяем наше расширение к этой линии.

1
2
    $(evt.target).children().slideDown().end().removeClass(«collapsed»);
});

В противоположность нашему обработчику событий коллапса , в обработчике событий расширения мы сдвигаем все дочерние элементы элементов каталога и удаляем свернутый класс из нашего целевого элемента. Собираем все вместе.

1
2
3
4
5
$(«#tree li:parent»).bind(«collapse», function(evt) {
    $(evt.target).children().slideUp().end().addClass(«collapsed»);
}).bind(«expand», function(evt) {
    $(evt.target).children().slideDown().end().removeClass(«collapsed»);
});

Только этот код ничего не сделает для нас, потому что события разворачиваются и разворачиваются , неизвестны и понятия не имеют, когда их отправлять. Поэтому мы добавляем наш метод .trigger (), когда хотим, чтобы эти события запускались.

1
2
3
4
5
6
7
8
9
$(«#tree li:parent»).bind(«collapse», function(evt) {
    $(evt.target).children().slideUp().end().addClass(«collapsed»);
}).bind(«expand», function(evt) {
    $(evt.target).children().slideDown().end().removeClass(«collapsed»);
})).toggle(function() { // toggle between
    $(this).trigger(«collapse»);
}, function() {
    $(this).trigger(«expand»);
});

Если мы запустим этот код, наши каталоги теперь будут переключаться при нажатии между активацией события разворачивания и развертывания . Но если вы щелкнете по вложенному каталогу, вы заметите, что наши события запускаются несколько раз за клик. Это из-за пузыря событий.


Когда вы щелкаете элемент на странице, событие перемещается или захватывается от самого верхнего родителя, к которому прикреплено событие, к намеченной цели. Это тогда пузыри от намеченной цели назад самый верхний родитель.

Например, когда мы щелкаем папку css /, наше событие записывается через root /, assets /, а затем css /. Затем он отправляет пузыри css /, assets /, затем в root /. Следовательно, обработчик выполняется три раза. Мы можем исправить это, добавив простое условие в обработчик для намеченной цели.

1
2
3
4
if(evt.target == evt.currentTarget)
{
    (evt.target).children().slideUp().end().addClass(«collapsed»);
}

Этот код будет проверять каждую текущую цель события относительно намеченной цели или currentTarget. Когда у нас есть совпадение, только тогда скрипт выполнит событие коллапса. После обновления события разворачивания и развертывания наша страница будет функционировать, как и ожидалось.


Пространство имен обеспечивает контекст для событий. Пользовательские события, свернутые и развернутые , неоднозначны. Добавление пространства имен в пользовательское событие jQuery — это структурированное имя события, за которым следует пространство имен . Мы создадим наше пространство имен под названием TreeEvent, потому что наши события представляют действия и функциональные возможности древовидной структуры папок. После того, как мы добавили пространства имен к нашим событиям, код теперь будет выглядеть так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
$(«#tree li:parent»).bind(«collapse.TreeEvent», function(evt) {
    if(evt.target == evt.currentTarget)
    {
        $(evt.target).children().slideUp().end().addClass(«collapsed»);
    }
}).bind(«expand.TreeEvent», function(evt) {
    if(evt.target == evt.currentTarget)
    {
        $(evt.target).children().slideDown().end().removeClass(«collapsed»);
    }
}).toggle(function() {
    $(this).trigger(«collapse.TreeEvent»);
}, function() {
    $(this).trigger(«expand.TreeEvent»);
});

Все, что нам нужно было изменить, — это имена событий в методах .bind () и .trigger () как для событий разворачивания, так и для разворачивания . Теперь у нас есть функциональный пример использования пользовательских событий в пространстве имен.

Обратите внимание, что мы можем легко удалить события из элементов, используя метод unbind ().

1
2
$(«#tree li:parent»).unbind(«collapse.TreeEvent»);
$(«#tree li:parent»).unbind(«.TreeEvent»);

Другой способ настроить пользовательское событие в jQuery — использовать API специальных событий . По этому API не так много документации, но Брэндом Аарон, основной участник jQuery, написал две отличные публикации в блоге ( http://brandonaaron.net/blog/2009/03/26/special-events и http: / /brandonaaron.net/blog/2009/06/4/jquery-edge-new-special-event-hooks ), чтобы помочь нам понять доступные методы. Ниже приводится краткое объяснение методов.

  • add — аналогично настройке, но вызывается для каждого связываемого события.
  • setup — вызывается, когда событие связано.
  • удалить — аналогично разрыву, но вызывается для каждого события, которое не связано.
  • teardown — вызывается, когда событие не связано.
  • обработчик — вызывается при отправке события.

Теперь давайте посмотрим, как мы можем объединить наши пользовательские события в специальное событие, которое мы будем называть toggleCollapse .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
jQuery.event.special.toggleCollapse = {
    setup: function(data, namespaces) {
        for(var i in namespaces)
        {
            if(namespaces[i] == «TreeEvent»)
            {
                jQuery(this).bind(‘click’, jQuery.event.special.toggleCollapse.TreeEvent.handler);
            }
        }
    },
     
    teardown: function(namespaces) {
        for(var i in namespaces)
        {
            if(namespaces[i] == «TreeEvent»)
            {
                jQuery(this).unbind(‘click’, jQuery.event.special.toggleCollapse.TreeEvent.handler);
            }
        }
    },
         
    TreeEvent: {
        handler: function(event) {
            if(event.target == event.currentTarget)
            {
                var elt = jQuery(this);
                var cssClass = «collapsed»;
                if(elt.hasClass(cssClass))
                {
                    elt.children().slideDown().end().removeClass(cssClass);
                }
                else
                {
                    elt.children().slideUp().end().addClass(cssClass);
                }
                 
                event.type = «toggleCollapse»;
                jQuery.event.handle.apply(this, arguments);
            }
        }
    }
};
 
$(«#tree li:parent»).bind(«toggleCollapse.TreeEvent», function(evt) {});

Давайте посмотрим на это раздел за разделом.

01
02
03
04
05
06
07
08
09
10
jQuery.event.special.toggleCollapse = {
    setup: function(data, namespaces) {
        for(var i in namespaces)
        {
            if(namespaces[i] == «TreeEvent»)
            {
                jQuery(this).bind(‘click’, jQuery.event.special.toggleCollapse.TreeEvent.handler);
            }
        }
    },

Первая строка jQuery.event.special.toggleCollapse создает новое специальное событие с именем toggleCollapse . Затем у нас есть метод установки, который перебирает все пространства имен этого события. Как только он находит TreeEvent , он связывает событие click с соответствующими элементами, которые при вызове события будут вызывать jQuery.event.special.toggleCollapse.TreeEvent.handler . Обратите внимание, что мы используем событие click в отличие от функции toggle (), которую мы использовали раньше. Это связано с тем, что toggle () — это не событие, а вспомогательная функция взаимодействия.

1
2
3
4
5
6
7
8
9
teardown: function(namespaces) {
    for(var i in namespaces)
    {
        if(namespaces[i] == «TreeEvent»)
        {
            jQuery(this).unbind(‘click’, jQuery.event.special.toggleCollapse.TreeEvent.handler);
        }
    }
},

Наш метод разрыва аналогичен нашему методу настройки, но вместо этого мы открепим событие click от всех соответствующих элементов.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
    TreeEvent: {
        handler: function(event) {
            if(event.target == event.currentTarget)
            {
                var elt = jQuery(this);
                var cssClass = «collapsed»;
                if(elt.hasClass(cssClass))
                {
                    elt.children().slideDown().end().removeClass(cssClass);
                }
                else
                {
                    elt.children().slideUp().end().addClass(cssClass);
                }
                 
                event.type = «toggleCollapse»;
                jQuery.event.handle.apply(this, arguments);
            }
        }
    }
};

Здесь мы используем пространство имен TreeEvent для абстрагирования обработчика. В обработчике мы переключаемся между свернутым и расширенным состоянием в зависимости от того, содержит ли соответствующий элемент класс CSS «свернутый». Наконец, мы устанавливаем тип события равным нашему имени события toggleCollapse и используем метод apply (), который будет выполнять аргумент обратного вызова, когда мы связываем это специальное событие.

1
$(«#tree li:parent»).bind(«toggleCollapse.TreeEvent», function(evt) {});

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


Ниже приведены несколько дополнительных ресурсов, которые могут оказаться полезными при работе с пользовательскими событиями. Спасибо за прочтение!

  • Подпишитесь на нас в Твиттере или подпишитесь на ленту Nettuts + RSS для получения лучших учебных материалов по веб-разработке.