Статьи

Раскрытие скрытых возможностей jQuery

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

Когда вы называете «jQuery», что происходит?

Сама функция jQuery очень проста:

1
2
3
4
jQuery = function (selector, context) {
    // The jQuery object is actually just the init constructor ‘enhanced’
    return new jQuery.fn.init(selector, context);
};

Под своей оболочкой функция jQuery (обычно называемая функцией-оберткой) просто возвращает экземпляр объекта jQuery, то есть экземпляр конструктора jQuery.fn.init .

Это полезно знать; с помощью этой информации мы знаем, что каждый раз, когда мы вызываем jQuery, мы на самом деле создаем совершенно уникальный объект с набором свойств. Умный jQuery дает объект, который можно рассматривать как массив. Каждый из ваших элементов (все вместе, обычно известный как «коллекция») упоминается внутри объекта под числовым индексом, как и внутри массива. И jQuery также дает этому объекту свойство length , как и следовало ожидать от массива. Это открывает мир возможностей. Во -первых , это означает, что мы можем позаимствовать некоторую функциональность из Array.prototype . Хороший пример этого — метод slice в jQuery, модифицированный из исходного кода:

1
2
3
4
5
6
7
8
9
/* … jQuery.fn.extend({ … */
slice: function() {
    return this.pushStack(
        Array.prototype.slice.apply( this, arguments ),
        «slice»,
        Array.prototype.slice.call(<WBR>arguments).join(«,»)
    );
},
/* … */

Для нативного метода «slice» не важно, что «this» не является реальным массивом — он подойдет для всего, что имеет свойство «length» и [0] , [1] , [2] и т. Д.

В этом объекте jQuery есть и другие интересные свойства — «.selector» и «.context» в большинстве случаев будут отражать аргументы, которые вы передаете в «jQuery (…)» .

1
2
var jqObject = jQuery(‘a’);
jqObject.selector;

Важно отметить, что jQuery иногда предоставляет новые объекты jQuery для работы. Если вы запустите метод, который каким-либо образом изменяет коллекцию, например, «.parents ()» , то jQuery не изменит текущий объект; он просто передаст вам совершенно новый:

1
2
3
4
var originalObject = jQuery(‘a’);
var anotherObject = originalObject.parents();
 
originalObject === anotherObject;

Все методы, которые каким-то образом изменяют коллекцию, возвращают совершенно новый объект jQuery — вы все равно можете получить доступ к старому объекту через ‘.end ()’ или, более подробно, через ‘.prevObject’ .

Центральным в возможностях DOM jQuery является синтаксис создания его элементов. 1.4 принес совершенно новый способ быстро и лаконично создавать свои элементы. Например

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
var myDiv = jQuery(‘<div/>’, {
    id: ‘my-new-element’,
    class: ‘foo’,
    css: {
        color: ‘red’,
        backgrondColor: ‘#FFF’,
        border: ‘1px solid #CCC’
    },
    click: function() {
        alert(‘Clicked!’);
    },
    html: jQuery(‘<a/>’, {
        href: ‘#’,
        click: function() {
            // do something
            return false;
        }
    })
});

Начиная с версии 1.4, вы можете передать второй аргумент функции jQuery при создании элемента — передаваемый вами объект, по большей части, будет действовать так, как если бы вы передавали его в «.attr (…)» , Тем не менее, jQuery отобразит некоторые свойства в свои собственные методы, например, свойство «click» сопоставляется с методом «click» jQuery (который связывает обработчик события для события «click» ), а «css» сопоставляется с «jQuery ». метод css и т. д.

Чтобы проверить, какие свойства соответствуют методам jQuery, откройте консоль и введите «jQuery.attrFn» .

jQuery предоставляет метод, который вы можете использовать для сериализации всех входных данных в одной или нескольких формах. Это полезно при отправке данных через XHR («Ajax»). Это было в jQuery в течение долгого времени, но об этом не часто говорят, и так много разработчиков не понимают, что это там. Отправка всей формы через Ajax с использованием jQuery не может быть проще:

1
2
3
4
var myForm = $(‘#my-form’);
jQuery.post(‘submit.php’, myForm.serialize(), function(){
    alert(‘Data has been sent!’);
});

jQuery также предоставляет метод ‘serializeArray’ , который предназначен для использования с несколькими формами, и вспомогательную функцию ‘param’ (в пространстве имен jQuery), которая принимает обычный объект и возвращает строку запроса, например

1
2
3
4
5
6
7
var data = {
    name: ‘Joe’,
    age: 44,
    profession: ‘Web Developer’
};
 
jQuery.param(data);

Метод «animate» в jQuery, вероятно, является наиболее гибким из методов jQuery. С его помощью можно анимировать практически все, не только свойства CSS и не только элементы DOM. Вот как вы обычно используете «animate» :

1
2
3
4
jQuery(‘#box’).animate({
    left: 300,
    top: 300
});

Когда вы указываете свойство для анимации (например, ‘top’ ), jQuery проверяет, анимируете ли вы что-либо с помощью свойства style ( ‘element.style’ ), и проверяет, определено ли указанное свойство ( ‘top’ ) в ‘style’ — если это не так, jQuery просто обновляет ‘top’ для самого элемента. Вот пример:

1
2
3
4
jQuery(‘#box’).animate({
    top: 123,
    foo: 456
});

«top» является допустимым свойством CSS, поэтому jQuery обновит «element.style.top» , но «foo» не является допустимым свойством CSS, поэтому jQuery просто обновит «element.foo» .

Мы можем использовать это в наших интересах. Скажем, например, что вы хотите анимировать квадрат на холсте. Сначала давайте определим простой конструктор и метод ‘draw’, который будет вызываться на каждом этапе анимации:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
function Square(cnvs, width, height, color) {
 
    this.x = 0;
    this.y = 0;
    this.width = width;
    this.height = height;
    this.color = color;
     
    this.cHeight = cnvs.height;
    this.cWidth = cnvs.width;
    this.cntxt = cnvs.getContext(‘2d’);
     
}
 
Square.prototype.draw = function() {
 
    this.cntxt.clearRect(0, 0, this.cWidth, this.cHeight);
    this.cntxt.fillStyle = this.color;
    this.cntxt.fillRect(this.x, this.y, this.width, this.height);
     
};

Мы создали конструктор «Квадрат» и один из его методов. Создание холста и его анимация не могут быть проще:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
// Create a <canvas/> element
var canvas = $(‘<canvas/>’).appendTo(‘body'<WBR>)[0];
canvas.height = 400;
canvas.width = 600;
 
// Instantiate Square
var square = new Square(canvas, 70, 70, ‘rgb(255,0,0)’);
 
jQuery(square).animate({
    x: 300,
    y: 200
}, {
    // ‘draw’ should be called on every step
    // of the animation:
    step: jQuery.proxy(square, ‘draw’),
    duration: 1000
});

Это очень простой эффект, но он четко демонстрирует возможности. Вы можете увидеть это в действии здесь: http://jsbin.com/ocida (это будет работать только в браузерах, которые поддерживают холст HTML5)

Все служебные функции jQuery Ajax ( jQuery.ajax , jQuery.get , jQuery.post ) возвращают объект XMLHttpRequest, который можно использовать для выполнения последующих операций по любому запросу. Например:

01
02
03
04
05
06
07
08
09
10
11
12
13
var curRequest;
 
jQuery(‘button.makeRequest’).<WBR>click(function(){
    curRequest = jQuery.get(‘foo.php’, function(response){
        alert(‘Data: ‘ + response.responseText);
    });
});
 
jQuery(‘button.cancelRequest’)<WBR>.click(function(){
    if (curRequest) {
        curRequest.abort();
    }
});

Здесь мы делаем запрос всякий раз, когда нажимается кнопка «makeRequest» — и мы отменяем активный запрос, если пользователь нажимает кнопку «cancelRequest» .

Другое потенциальное использование для синхронных запросов:

1
2
3
4
5
6
var myRequest = jQuery.ajax({
    url: ‘foo.txt’,
    async: false
});
 
console.log(myRequest.<WBR>responseText);

Узнайте больше об объекте «XMLHttpRequest», а также обязательно ознакомьтесь с утилитами jQuery Ajax .

В jQuery есть встроенный механизм организации очереди, который используется всеми его методами анимации (все из которых действительно используют animate () ). Эта очередь может быть легко проиллюстрирована простой анимацией:

1
2
3
4
5
jQuery(‘a’).hover(function(){
    jQuery(this).animate({<WBR>paddingLeft:’+=15px’});
}, function(){
    jQuery(this).animate({<WBR>paddingLeft:’-=15px’});
});

Быстрое наведение курсора на группу якорей и последующее наведение на них снова приведет к тому, что анимации будут стоять в очереди и появляться по одному — я уверен, что многие из вас уже видели этот эффект очереди раньше. Если нет, проверьте это здесь: http://jsbin.com/aqaku

Метод ‘queue’ похож на известный метод ‘each’ в том, как он вызывается. Вы передаете функцию, которая в конечном итоге будет вызываться для каждого из элементов в коллекции:

1
2
3
jQuery(‘a’).queue(function(){
    jQuery(this).addClass(‘all-<WBR>done’).dequeue();
});

Передача только функции в очередь вызовет добавление этой функции в очередь по умолчанию ‘fx’ , то есть в очередь, используемую всеми анимациями, выполняемыми jQuery. Следовательно, эта функция не будет вызываться до тех пор, пока не будут завершены все текущие анимации, встречающиеся в каждом элементе в коллекции (в данном случае все якоря).

Обратите внимание, что мы добавляем класс ‘all-done’ в функцию выше. Как указано, этот класс будет добавлен только после завершения всех текущих анимаций. Мы также вызываем метод ‘dequeue’ . Это очень важно , так как это позволит jQuery продолжить работу с очередью (то есть, он даст jQuery знать, что вы закончили с тем, что вы делаете). jQuery 1.4 предоставляет другой способ продолжения очереди; вместо вызова dequeue просто вызовите первый аргумент, переданный вашей функции:

1
2
3
4
jQuery(‘a’).queue(function(<WBR>nextItemInQueue){
    // Continue queue:
    nextItemInQueue();
});

Это делает то же самое, хотя это немного более полезно в том смысле, что его можно вызывать где угодно в вашей функции, даже в беспорядке замыканий (которые обычно уничтожают ключевое слово ‘this’ ). Конечно, в pre-jQuery-1.4 вы могли просто сохранить ссылку на ‘this’ , но это было бы немного утомительно.

Чтобы добавить функцию в пользовательскую очередь, просто передайте имя пользовательской очереди в качестве первого аргумента и функцию в качестве второго:

1
2
3
4
jQuery(‘a’).queue(‘<WBR>customQueueName’, function(){
    // Do stuff
    jQuery(this).dequeue(‘<WBR>customQueueName’);
});

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

Узнайте больше о ‘queue’ , ‘dequeue’ и ‘jQuery.queue’ .

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

Чтобы добавить пространство имен при регистрации обработчика событий, просто добавьте к имени события точку с точкой, а затем свое уникальное пространство имен (например, « .fooPlugin » ):

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
jQuery.fn.foo = function() {
     
    this.bind(‘click.fooPlugin’, function() {
        // do stuff
    });
      
    this.bind(‘mouseover.<WBR>fooPlugin’, function() {
        // do stuff
    });
     
    return this;
};
 
// Use the plugin:
jQuery(‘a’).foo();
 
// Destroy its event handlers:
jQuery(‘a’).unbind(‘.<WBR>fooPlugin’);

Передача только пространства имен для «unbind» отменит все обработчики событий с этим пространством имен.

Так какие из них я пропустил? Какие полезные функции, по вашему мнению, недостаточно хорошо документированы в jQuery? Давайте обсудим в комментариях!