Еще чуть-чуть о полезном инструментарии: есть такой классный плагин – jQuery-inlog [http://prinzhorn.github.com/jquery-inlog/] – основное его назначение — дать нам чуть-чуть больше понимания о происходящем внутри самого jQuery, вот кусочек HTML:
<body> <div class="bar"> <div class="bar"> <div id="foo"></div> </div> </div> <div id="bacon"></div> </body>
А вот и код, который его обслуживает:
$l(true);
$("#foo").parents(".bar").next().prev().parent().fadeOut();
$l(false);
Какие-то странные манипуляции, для какого же элемента будет применён метод "fadeout()"? Для выяснения оного наш код обёрнут в вызов метода "$l()". "$l()" — это и есть собственно вызов плагина, результат его работы можно найти в консоли:
У данного плагина есть ещё настройки, которые регулируют объём информации выводимой в консоль.
Пример и скриншот взять с официальной документации по плагину
jQuery UI представляет из себя набор виджетов и плагинов от самих разработчиков jQuery. По моему мнению, данный инструмент необходимо изучить настолько, насколько это требуется чтобы не писать свои "велосипеды". Скачать-почитать о данной надстройке над jQuery можно на домашней страницы проекта – http://jqueryui.com/
Что нам необходимо знать о виджетах и плагинах? Первое – это какие они есть, и второе – как работают. На этих двух моментах я и постараюсь остановиться.
Начну с полезных плагинов, которые могут упростить жизнь при создании интерактивных интерфейсов:
Виджеты – это уже комплексное решение содержащие не только JavaScript код, но и некую HTML и CSS реализацию:
<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Accordion</title>
<link rel="profile" href="http://gmpg.org/xfn/11"/>
<link rel="shortcut icon" href="http://anton.shevchuk.name/favicon.ico"/>
<link rel="stylesheet" href="css/styles.css"/>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/code.js"></script>
<script type="text/javascript">
$(function(){
var toDisplay = 1;
$("article h2").click(function(){
var $this = $(this);
$this
.next("p")
.slideToggle("slow")
.siblings("p:visible")
.slideUp("slow");
$this.toggleClass("active");
$this.siblings("h2").removeClass("active");
})
.eq(toDisplay).addClass("active")
.next().show();
});
</script>
<style type="text/css">
article h2 {
background: #e9e7e7 url(images/arrows.png) no-repeat 618px 7px;
padding: 7px 15px;
margin: 0;
border: solid 1px #c4c4c4;
border-bottom: none;
cursor: pointer;
}
article h2:hover {
background-color: #e3e2e2;
}
article h2.active {
background-position: 618px -23px;
}
article p {
display: none;
margin: 0;
padding: 10px 15px 20px;
}
</style>
</head>
<body>
<div id="content" class="wrapper box">
<menu>
<a href="index.html" title="go prev" class="button alignleft" rel="prev">← Back </a>
<a href="index.html" title="back to Index" class="button alignleft" rel="index">Index §</a>
<a href="#" title="reload" class="button alignleft" onclick="window.location.reload();return false">Reload ¤</a>
<a href="tabs.html" title="go next" class="button alignright" rel="next">Next →</a>
</menu>
<header>
<h1>Реализация аккордиона</h1>
<h2>На jQuery без использования jQuery UI</h2>
</header>
<article>
<h2>Article Title</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus rutrum,
lectus eu varius consectetur, libero velit hendrerit augue, ut posuere enim neque
in libero. Donec eget sagittis nibh. Suspendisse sed tincidunt urna. Cras quis
euismod neque. Maecenas auctor ultricies posuere. Pellentesque luctus pulvinar dui
eget semper. Donec sodales odio eu sapien varius luctus. Donec dictum feugiat diam
at malesuada. Sed nec massa in augue condimentum faucibus quis ut diam. Quisque
nisl sem, semper nec vulputate vel, mattis sit amet justo. Aliquam purus felis,
tempor at scelerisque quis, tincidunt in neque. Etiam ut risus diam. Pellentesque
fermentum risus id elit feugiat cursus. Ut fringilla dictum diam, sed iaculis
lorem pulvinar ut. Cras vel elit id velit commodo viverra sit amet vel orci.</p>
<h2>Article Title</h2>
<p>Duis in vestibulum sem. Cras euismod tincidunt dui, et scelerisque tellus condimentum vel.
Maecenas et urna sit amet risus fermentum rhoncus nec porttitor ligula. Maecenas sit amet
turpis enim, ut iaculis est. Duis feugiat, lacus id placerat porttitor, lorem augue gravida
nisi, eu porta eros risus et lectus. Maecenas vestibulum nunc vel ipsum tincidunt sit amet
blandit sapien bibendum. Proin vel vulputate nisl. Duis tempor imperdiet placerat. Pellentesque
faucibus consequat magna, et bibendum nisl egestas non. Pellentesque sit amet mattis augue.
Aenean at diam tincidunt purus sollicitudin gravida non in nisi. Fusce bibendum, magna in
adipiscing mattis, sem risus fringilla mi, nec gravida lectus lectus at nibh. Suspendisse
adipiscing elementum laoreet. Suspendisse sem erat, varius quis aliquet vitae, dapibus sed
nibh. Nullam iaculis sem at mauris faucibus in vestibulum libero pretium. Aliquam eu turpis
libero. Fusce et ultrices lectus.</p>
<h2>Article Title</h2>
<p>Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
Morbi dapibus, dui in consequat pulvinar, nunc erat consequat ipsum, ut blandit nulla eros ac purus.
In at justo sed lorem consequat fermentum. Nunc scelerisque purus sed neque rutrum adipiscing. Sed
vehicula tristique dolor, quis porttitor magna dictum eu. Cras tristique erat non orci aliquam tempor.
In hac habitasse platea dictumst. Nam eget sodales neque. Aenean adipiscing consequat diam, eu
molestie diam dictum eu.</p>
</article>
<footer>
©copyright 2014 Anton Shevchuk — <a href="http://anton.shevchuk.name/jquery-book/">jQuery Book</a>
</footer>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1669896-2']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</body>
</html>

<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tabs</title>
<link rel="profile" href="http://gmpg.org/xfn/11"/>
<link rel="shortcut icon" href="http://anton.shevchuk.name/favicon.ico"/>
<link rel="stylesheet" href="css/styles.css"/>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/code.js"></script>
<script type="text/javascript">
$(function(){
var hash = window.location.hash;
$("article li a").click(function(){
var $this = $(this);
var $pan = $("article").find($this.attr('href'));
if (!$this.hasClass('active')) {
$("article li a").removeClass("active");
$("article p").hide();
$this.addClass("active");
$pan.show();
window.location.hash = $this.attr('href');
}
return false;
});
if (hash $("article li a[href="+hash+"]").length) {
$("article li a[href="+hash+"]").click();
} else {
$("article li a").eq(0).click();
}
});
</script>
<style type="text/css">
article ul {
padding: 0 15px 0;
margin-bottom: -1px;
overflow: hidden;
}
article li {
float:left;
list-style: none;
margin: 0 4px;
}
article li a {
display: block;
padding: 4px 8px;
background: #f5f5f5;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 2px 2px 0 0;
}
article p {
clear: both;
display: none;
margin: 0 4px;
padding: 10px 15px 20px;
border: 1px solid #ccc;
border-radius: 2px;
}
article a.active {
background: #fff;
border-bottom: 1px solid #fff;
}
</style>
</head>
<body>
<div id="content" class="wrapper box">
<menu>
<a href="accordion.html" title="go prev" class="button alignleft" rel="prev">← Prev </a>
<a href="index.html" title="back to Index" class="button alignleft" rel="index">Index §</a>
<a href="#" title="reload" class="button alignleft" onclick="window.location.reload();return false">Reload ¤</a>
<a href="widget.html" title="go next" class="button alignright" rel="next">Next →</a>
</menu>
<header>
<h1>Реализация закладок</h1>
<h2>На jQuery без использования jQuery UI</h2>
</header>
<article>
<ul>
<li><a href="#pan1">First Article</a></li>
<li><a href="#pan2">Second Article</a></li>
<li><a href="#pan3">Third Article</a></li>
</ul>
<p id="pan1">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus rutrum,
lectus eu varius consectetur, libero velit hendrerit augue, ut posuere enim neque
in libero. Donec eget sagittis nibh. Suspendisse sed tincidunt urna. Cras quis
euismod neque. Maecenas auctor ultricies posuere. Pellentesque luctus pulvinar dui
eget semper. Donec sodales odio eu sapien varius luctus. Donec dictum feugiat diam
at malesuada. Sed nec massa in augue condimentum faucibus quis ut diam. Quisque
nisl sem, semper nec vulputate vel, mattis sit amet justo. Aliquam purus felis,
tempor at scelerisque quis, tincidunt in neque. Etiam ut risus diam. Pellentesque
fermentum risus id elit feugiat cursus. Ut fringilla dictum diam, sed iaculis
lorem pulvinar ut. Cras vel elit id velit commodo viverra sit amet vel orci.</p>
<p id="pan2">Duis in vestibulum sem. Cras euismod tincidunt dui, et scelerisque tellus condimentum vel.
Maecenas et urna sit amet risus fermentum rhoncus nec porttitor ligula. Maecenas sit amet
turpis enim, ut iaculis est. Duis feugiat, lacus id placerat porttitor, lorem augue gravida
nisi, eu porta eros risus et lectus. Maecenas vestibulum nunc vel ipsum tincidunt sit amet
blandit sapien bibendum. Proin vel vulputate nisl. Duis tempor imperdiet placerat. Pellentesque
faucibus consequat magna, et bibendum nisl egestas non. Pellentesque sit amet mattis augue.
Aenean at diam tincidunt purus sollicitudin gravida non in nisi. Fusce bibendum, magna in
adipiscing mattis, sem risus fringilla mi, nec gravida lectus lectus at nibh. Suspendisse
adipiscing elementum laoreet. Suspendisse sem erat, varius quis aliquet vitae, dapibus sed
nibh. Nullam iaculis sem at mauris faucibus in vestibulum libero pretium. Aliquam eu turpis
libero. Fusce et ultrices lectus.</p>
<p id="pan3">Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
Morbi dapibus, dui in consequat pulvinar, nunc erat consequat ipsum, ut blandit nulla eros ac purus.
In at justo sed lorem consequat fermentum. Nunc scelerisque purus sed neque rutrum adipiscing. Sed
vehicula tristique dolor, quis porttitor magna dictum eu. Cras tristique erat non orci aliquam tempor.
In hac habitasse platea dictumst. Nam eget sodales neque. Aenean adipiscing consequat diam, eu
molestie diam dictum eu.</p>
</article>
<footer>
©copyright 2014 Anton Shevchuk — <a href="http://anton.shevchuk.name/jquery-book/">jQuery Book</a>
</footer>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1669896-2']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</body>
</html>
На этом обзор виджетов можно считать законченным, вернёмся к плагинам.
Все виджеты и плагины завязаны на ядро jQuery UI, но есть так же зависимости между самими плагинами и стоит о них помнить. Но не переживайте – при сборке jQuery UI пакета все зависимости проверяются автоматически, т.е. когда вам потребуется доселе неподключенный виджет, лучше скачать сборку заново.
Утилит у нас не много – вот полезный плагин – position, который позволяет контролировать положение DOM элементов – http://jqueryui.com/position/, а ещё есть фабрика по созданию виджетов, но о ней я расскажу чуть попозже.
Среди эффектов предоставляемых jQuery UI я выделяю четыре пункта:
За анимацию цвета отвечает компонент "Effects Core", который позволяет анимировать изменения цвета посредством использования функции "animate()":
$("#my").animate({ backgroundColor: "black" }, 1000);
Да-да, jQuery из коробки не умеет этого делать, а вот jQuery UI позволяет анимировать следующие параметры:
Ещё одной возможностью заключенной в "Effects Core" является анимация изменений класса DOM элемента, т.е. когда вы будете присваивать новый класс элементу, то вместо обычного моментального применения новых CSS свойств вы будете наблюдать анимацию этих свойств от текущих до заданных в присваиваемом классе. Для использования данного функционала нам потребуются старые знакомые – методы "addClass()", "toggleClass()" и "removeClass()", с одной лишь разницей – при вызове метода вторым параметром должна быть указана скорость анимации:
$("#my").addClass("active", 1000);
$("#my").toggleClass("active", 1000);
$("#my").removeClass("active", 1000);
Если из предыдущего абзаца у вас не возникло понимания сути происходящего, то этот код для вас:
<style>
#my {
font-size:14px;
}
#my.active {
font-size:20px;
}
</style>
<script>
$(function (){
$("#my").addClass("active", 1000);
// тут получается аналогично следующему вызову
$("#my").animate({"font-size":"20px"}, 1000);
});
</script>
А ещё появляется метод switchClass(removeClass, addClass, duration), который заменяет один класс другим, но мне он ни разу не пригодился.
О наборе эффектов я не буду долго рассказывать, их лучше посмотреть в действии на странице http://jqueryui.com/effect/. Для работы с эффектами появляется метод "effect()", но сам по себе его лучше не использовать, ведь UI расширил функционал встроенных методов "show()", "hide()" и "toggle()", теперь, передав в качестве параметра скорости анимации названия эффекта вы получите необходимый результат:
$("#my").hide("puff");
$("#my").show("transfer");
$("#my").toggle("explode");
Приведу список эффектов, может кто запомнит: blind, bounce, clip, drop, explode, fold, highlight, puff, pulsate, scale, shake, size, slide, transfer.
Помните, я в главе о анимации рассказывал о easing и одноименном плагине для jQuery? Так вот UI тоже расширяет easing, так что подключив его можно отключать плагин. И да, этот функционал завязан лишь на "Effects Core".
Одной из самых замечательных особенностей jQuery UI является возможность менять "шкурки" всех виджетов разом, и для этого даже предусмотрена специальная утилита – ThemeRoller [http://jqueryui.com/themeroller/]:
Если в какой-то момент времени потребуется внести изменения в тему, то откройте файл jquery-ui-#.#.##-custom.css и найдёте строчку начинающуюся с текста "To view and modify this theme, visit http://..." и таки пройдите по указанной ссылке, и уже используя ThemeRoller внесите необходимые изменения.
Отправной точкой при написания виджета для jQuery UI для вас будет официальная документация, но поскольку со знанием английского не у всех сложилось, то я постараюсь перевести и адаптировать информацию изложенную в ней.
Первое, о чём стоит рассказать, это то, что правила написания плагинов для jQuery слишком вальяжны, что не способствует их качеству. При создании jQuery UI, походу, решили пойти путём стандартизации процесса написания плагинов и виджетов, я не могу сказать насколько задумка удалась, но стало явно лучше чем было. Начну с описания каркаса для вашего виджета:
$.widget("book.expose", {
// настройки по умолчанию
options: {
color: "red"
},
// инициализация widget
// вносим изменения в DOM и вешаем обработчики
_create: function() {
this.element; // искомый объект в jQuery обёртке
this.name; // имя - expose
this.namespace; // пространство – book
this.element.on("click."+this.eventNamespace, function(){
console.log("click");
})
},
// метод отвечает за применение настроек
_setOption: function( key, value ) {
// применяем изменения настроек
this._super("_setOption", key, value );
},
// метод _destroy должен быть антиподом к _create
// он должен убрать все изменения внесенные изменения в DOM
// и убрать все обработчики, если таковые были
_destroy: function() {
this.element.unbind('.'+this.eventNamespace);
}
});
Поясню для тех кто не прочёл комментарии:
options – хранилище настроек виджета для конкретного элемента_create() – отвечает за инициализацию виджета – тут должны
происходить изменения в DOM'е, и "вешаться" обработчики событий_destroy() – антипод для "_create()" – должен подчистить всё, что мы
намусорили_setOption(key, value) – данный метод будет вызван при попытке
изменить какие-либо настройки:$("#my").expose({key:value})
Наблюдательный глаз заметит, что все перечисленные методы начинаются со знака подчёркивания – это такой способ выделить "приватные" методы, которые недоступны для запуска, и если мы попытаемся запустить "$('#my').expose('_destroy')", то получим ошибку. Но учтите – это лишь договорённость, соблюдайте, её!
Для обхода договорённости о приватности можно использовать метод "data()":
$("#my").data("expose")._destroy() // место для смайла "(evil)"
В данном примере, я постарался задать хороший тон написания виджетов – я "повесил" обработчики событий в namespace, это даст в дальнейшем возможность контролировать происходящее без необходимости залазить в код виджета, это "true story".
Код описанный в методе "_destroy()" – избыточен, т.к. он и так выполняется в публичном "destroy()", приведён тут для наглядности.
А для ленивых, чтобы не прописывать каждый раз "eventNamespace" в обработчиках событий, разработчики добавили в версии 1.9.0 два метода: "_on()" и "_off()", первый принимает два параметра:
Все перечисленные события будут "висеть" в пространстве "eventNamespace", т.е. результат будет предположительно одинаковым:
this._on(this.element, {
mouseover:function(event) {
console.log("Hello mouse");
},
mouseout:function(event) {
console.log("Bye mouse");
}
});
Второй метод – "_off()" – позволяет выборочно отключать обработчики:
this._off(this.element, "mouseout click");
Ну каркас баркасом, пора переходить к функционалу – добавим произвольную функцию с произвольным функционалом:
callMe:function(){
console.log("Allo?");
}
К данной функции мы легко сможем обращаться как из других методов виджета так и извне:
// изнутри
this.callMe()
// извне
$("#my").expose("callMe")
Если ваша функция принимает параметры, то передача оных осуществляется следующим способом:
$("#my").expose("callMe", "Hello!")
Если вы хотите достучаться в обработчике событий до метода виджета, то не забудьте про область видимости переменных, и сделайте следующий манёвр:
_create: function() {
var self = this; // вот он!
this.element.on("click."+this.eventNamespace, function(){
// тут используем self, т.к. this уже указывает на
// элемент по которому кликаем
self.callMe();
})
},
Хорошо идём, теперь поговорим о событиях – для более гибкой разработки и внедрения виджетов предусмотрен функционал по созданию произвольных событий и их "прослушиванию":
// инициируем событие
this._trigger("incomingCall");
// подписываемся на событие при инициализации виджета
$("#my").expose({
incommingCall: function(ev) {
console.log("din-don");
}
})
// или после, используя в качестве имени события
// имя виджета + имя события
$("#my").bind("exposeincomingCall", function(){
console.log("tru-lya-lya")
});
Материала много, я понимаю, но ещё добавлю описание нескольких методов которые можно вызвать из самого виджета:
_delay() – данная функция работает как "setTimeout()", вот только
контекст переданной функции будет указывать на сам виджет (это чтобы
не заморачиваться с областью видимости)
_hoverable() и _focusable() – данным методам необходимо скармливать
элементы для которых необходимо отслеживать события "hover" и
"focus", чтобы автоматически добавит к ним классы "ui-state-hover" и
"ui-state-focus" при наступлении оных
_hide() и _show() – эти два метода появились в версии 1.9.0, они созданы
дабы стандартизировать поведение виджетов при использовании
методов анимации, настройки принято прятать в опциях под ключами
"hide" и "show" соответственно. Использовать методы следует
следующим образом:
options: {
hide: {
effect: "slideDown", // настройки эквиваленты вызову
duration: 500 // .slideDown( 500)
}
}
// внутри виджета следует использовать вызовы _hide() и _show()
this._hide( this.element, this.options.hide, function() {
// это наша функция обратного вызова
console.log('спрятали');
});
Существует ещё пару методов, которые реализованы за нас:
enable: function() {
return this._setOption( "disabled", false );
},
disable: function() {
return this._setOption( "disabled", true );
},
Фактически, данный функции создают синоним для вызова:
$("#my").expose({ "disabled": true }) // или false
Наша задача сводится лишь к отслеживанию данного флага в методе "_setOption()".
Примеру быть, возможно этот виджет и не будет популярен, зато он наглядно демонстрирует как создавать виджеты для jQuery UI.
<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Пример widget'а для jQuery UI</title>
<link rel="profile" href="http://gmpg.org/xfn/11"/>
<link rel="shortcut icon" href="http://anton.shevchuk.name/favicon.ico"/>
<link rel="stylesheet" href="css/styles.css"/>
<style>
.expose-widget {
position: absolute;
z-index: 999;
background-color: rgba(0, 0, 0, 0.42);
display: none;
}
</style>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/jquery-ui.js"></script>
<script type="text/javascript" src="js/code.js"></script>
<script>
(function( $, undefined ) {
$.widget( "book.expose", {
version: "1.0.0",
// наши настройки
options: {
color: null, // цвет фона
speed: 500, // скорость анимации
show: 500, // настройки для метода _show()
hide: { // настройки для метода _hide()
effect: "fade",
duration: 500
}
},
// инициализация
_create: function() {
var self = this;
// выбранному элементу добавляем наш класс
// и вешаем обработчик события "клик"
this.element
.addClass( "book-widget" )
.on('click.expose-widget.'+this.eventNamespace, function() {
// вызываем метод виджета
// виджет доступен в переменной self
if (self.element.data('expose-it')) {
self.unmask();
} else {
self.mask();
}
return false;
});
// нам необходимо инициировать окружение лишь один раз для всех элементов
// это наш флаг
var totalInited = $.data(document.body, 'expose');
if (!totalInited) {
// изменяем флаг - у нас уже запущена инициализация
$.data(document.body, 'expose', 1);
// инициализация верхнего "бокса"
// и добавление в DOM
var $topBox = $('<div></div>');
$topBox.addClass("expose-widget");
$topBox.appendTo(document.body);
// сохраняем на него ссылку в реестре
$.data(document.body, 'topBox', $topBox);
// клонируем верхний бокс
// добавляем и сохраняем
var $bottomBox = $topBox.clone();
$bottomBox.appendTo(document.body);
$.data(document.body, 'bottomBox', $bottomBox);
// повторяем для левого
var $leftBox = $topBox.clone();
$leftBox.appendTo(document.body);
$.data(document.body, 'leftBox', $leftBox);
// и для правого
var $rightBox = $topBox.clone();
$rightBox.appendTo(document.body);
$.data(document.body, 'rightBox', $rightBox);
// все боксы разом
$allBox = $topBox.add($bottomBox).add($leftBox).add($rightBox);
$.data(document.body, 'allBox', $allBox);
// вешаем единый обработчик события для всех боксов
$(document.body).on('click.expose-widget', '.expose-widget', function() {
// вызов метода виджета
self.unmask();
return false;
});
// кидаем событие, на него можно подписаться лишь при инициализации виджета
// иначе толку не будет - будет поздно
this._trigger('build');
} else {
// отслеживаем кол-во виджетов
totalInited++;
$.data(document.body, 'expose', totalInited);
}
// вызываем метод виджета для применения цвета
this._setCurrentColor();
},
// ломаем всё что строили
_destroy: function() {
// подчищаем наш элемент
this.element
.removeClass( "book-widget" )
// данный метод избыточен, т.к. это делает за нас публичный метод destroy()
.off('.'+this.eventNamespace);
// декрементим кол-во инициализированных виджетов
var totalInited = $.data(document.body, 'expose');
totalInited--;
$.data(document.body, 'expose', totalInited);
// если больше нет виджетов
// удаляем вспомогательные боксы
if (totalInited==0) {
$.data(document.body, 'allBox').remove();
$(document.body).off('.expose-widget');
this._trigger('destroy');
}
},
// применяем настройки
_setOption: function( key, value ) {
if (key == 'disabled') {
// тут должен быть код по отключению виджета
}
if (key == 'speed') {
this.options.show = value;
this.options.hide.duration = value;
}
this._super( key, value );
},
// применяем настройки цвета
_setCurrentColor: function() {
this.options.color = $.data(document.body, 'topBox').css('background-color');
},
// изменяем цвет
color: function(value) {
$.data(document.body, 'allBox').css('background-color', value);
this._setCurrentColor();
},
// прячем боксы
unmask: function() {
var self = this;
// получаем набор
var $allBox = $.data(document.body, 'allBox');
// вызываем функцию анимации
this._hide($allBox, this.options.hide, function() {
// бросаем событие по завершению
self._trigger('unmask')
});
this._resetFlag();
// изменяем флаг
this.element.data('expose-it', false);
},
// показываем боксы
mask: function() {
var self = this;
// берём все "боксы"
var $allBox = $.data(document.body, 'allBox');
var $topBox = $.data(document.body, 'topBox');
var $bottomBox = $.data(document.body, 'bottomBox');
var $leftBox = $.data(document.body, 'leftBox');
var $rightBox = $.data(document.body, 'rightBox');
// вычисляем текущие координаты элемента и размеры окна
var offset = this.element.offset();
var height = this.element.outerHeight();
var width = this.element.outerWidth();
var winWidth = $(document).width();
var winHeight = $(document).height();
var topSettings = {
top:0,
left:0,
width:winWidth,
height:offset.top,
backgroundColor:this.options.color
};
var leftSettings = {
top:offset.top,
left:0,
width:offset.left,
height:height,
backgroundColor:this.options.color
};
var rightSettings = {
top:offset.top,
left:offset.left+width,
width:winWidth - (offset.left+width),
height:height,
backgroundColor:this.options.color
};
var bottomSettings = {
top:offset.top+height,
left:0,
width:winWidth,
height:winHeight - (offset.top+height),
backgroundColor:this.options.color
};
// проверяем - отображается у нас боксы в данный момент времени или нет
if ($topBox.is(':hidden')) {
// применяем настройки
$topBox.css(topSettings);
$leftBox.css(leftSettings);
$rightBox.css(rightSettings);
$bottomBox.css(bottomSettings);
// показываем все наши боксы
this._show( $allBox, this.options.show, function() {
// событие mask
self._trigger('mask');
});
} else {
this._resetFlag();
// применяем настройки через анимацию
$topBox.animate(topSettings, this.options.speed);
$leftBox.animate(leftSettings, this.options.speed);
$rightBox.animate(rightSettings, this.options.speed);
$bottomBox.animate(bottomSettings, this.options.speed, function(){
// событие mask
self._trigger('mask');
});
}
// изменяем флаг
this.element.data('expose-it', true);
},
_resetFlag:function() {
// workaround - надо "сбросить" флаг для всех других элементов
// надо будет придумать более красивое решение
$.each($.cache, function(i, el) {
if (el.data != undefined el.data.exposeIt != undefined) {
el.data.exposeIt = false;
}
});
}
});
})( jQuery );
</script>
</head>
<body>
<div id="content" class="wrapper box">
<menu label="Try...">
<a href="tabs.html" title="go prev" class="button alignleft" rel="prev">← Prev </a>
<a href="index.html" title="back to Index" class="button alignleft" rel="index">Index §</a>
<a href="#" title="reload" class="button alignleft" onclick="window.location.reload();return false">Reload ¤</a>
<hr/>
<pre><code><em>// run widget and try to click on article</em>
$(<span>'article'</span>).expose()</code></pre>
<button type="button" class="code">Run Code</button>
<pre><code contenteditable="true"><em>// configuration was changed</em>
$(<span>'article'</span>).expose({speed:2000})</code></pre>
<button type="button" class="code">Run Code</button>
<pre><code contenteditable="true"><em>// run widget and try to click on image</em>
$(<span>'article img'</span>).expose({speed:100})</code></pre>
<button type="button" class="code">Run Code</button>
<pre><code><em>// try widget API - trigger</em>
$(<span>'article:eq(0)'</span>).bind(<span>'exposemask'</span>,
function(){
$(this).css(<span>'color'</span>, <span>'red'</span>);
});
$(<span>'article:eq(0)'</span>).bind(<span>'exposeunmask'</span>,
function(){
$(this).css(<span>'color'</span>, <span>'black'</span>);
})</code></pre>
<button type="button" class="code">Run Code</button>
<pre><code><em>// try widget API - call method</em>
$(<span>'article:eq(1)'</span>).expose(<span>'mask'</span>)</code></pre>
<button type="button" class="code">Run Code</button>
<pre><code contenteditable="true"><em>// try widget API - call method+args</em>
$(<span>'article:eq(1)'</span>).expose(
<span>'color'</span>,
<span>'rgba(255, 0, 0, 0.5)'</span>
)</code></pre>
<button type="button" class="code">Run Code</button>
</menu>
<header>
<h1>widget</h1>
<h2>Пишем своё виджет для jQuery UI</h2>
</header>
<article>
<h2>Article</h2>
<p>
<img src="images/photo-bumblebee-tumb.jpg" alt="Bumblebee" class="left" width="200"/>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus rutrum,
lectus eu varius consectetur, libero velit hendrerit augue, ut posuere enim neque
in libero. Donec eget sagittis nibh. Suspendisse sed tincidunt urna. Cras quis
euismod neque. Maecenas auctor ultricies posuere. Pellentesque luctus pulvinar dui
eget semper. Donec sodales odio eu sapien varius luctus. Donec dictum feugiat diam
at malesuada. Sed nec massa in augue condimentum faucibus quis ut diam. Quisque
nisl sem, semper nec vulputate vel, mattis sit amet justo. Aliquam purus felis,
tempor at scelerisque quis, tincidunt in neque. Etiam ut risus diam. Pellentesque
fermentum risus id elit feugiat cursus. Ut fringilla dictum diam, sed iaculis
lorem pulvinar ut. Cras vel elit id velit commodo viverra sit amet vel orci.</p>
</article>
<article>
<h2>Article</h2>
<p>
<img src="images/photo-chamomile-tumb.jpg" alt="Chamomile" class="left" width="200"/>
Duis in vestibulum sem. Cras euismod tincidunt dui, et scelerisque tellus condimentum vel.
Maecenas et urna sit amet risus fermentum rhoncus nec porttitor ligula. Maecenas sit amet
turpis enim, ut iaculis est. Duis feugiat, lacus id placerat porttitor, lorem augue gravida
nisi, eu porta eros risus et lectus. Maecenas vestibulum nunc vel ipsum tincidunt sit amet
blandit sapien bibendum. Proin vel vulputate nisl. Duis tempor imperdiet placerat. Pellentesque
faucibus consequat magna, et bibendum nisl egestas non. Pellentesque sit amet mattis augue.
Aenean at diam tincidunt purus sollicitudin gravida non in nisi. Fusce bibendum, magna in
adipiscing mattis, sem risus fringilla mi, nec gravida lectus lectus at nibh. Suspendisse
adipiscing elementum laoreet. Suspendisse sem erat, varius quis aliquet vitae, dapibus sed
nibh. Nullam iaculis sem at mauris faucibus in vestibulum libero pretium. Aliquam eu turpis
libero. Fusce et ultrices lectus.</p>
</article>
<article>
<h2>Article</h2>
<p>
<img src="images/photo-maple-leaf-tumb.jpg" alt="Maple Leaf" class="left" width="200"/>
Ut consequat commodo mauris, eu dignissim justo congue vel. Etiam commodo tincidunt diam,
laoreet ullamcorper sapien egestas quis. Etiam auctor rutrum ante, at tincidunt elit lacinia
non. Pellentesque molestie tellus sit amet est sodales nec rutrum leo pharetra. Donec lacinia
ipsum vitae massa accumsan ullamcorper. Maecenas commodo lacus turpis. Proin sit amet mauris
sem, imperdiet faucibus lorem. Fusce ullamcorper consectetur ligula vel pretium. Sed et elit
vitae orci adipiscing condimentum id sed turpis. Morbi ultrices feugiat ullamcorper. Fusce at
magna dolor. Sed sit amet risus massa, quis imperdiet libero. Proin justo purus, sodales nec
cursus et, sollicitudin at nulla. Vivamus eget nibh tellus, sit amet facilisis ante.</p>
</article>
<footer>
©copyright 2014 Anton Shevchuk — <a href="http://anton.shevchuk.name/jquery-book/">jQuery Book</a>
</footer>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1669896-2']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</body>
</html>
Будьте внимательны, с выходом jQuery UI версии 1.9.0 были внесены правки в Widget API, следовательно, большинство доступной инфор- мации устарело, так что читайте официальную документацию [http://wiki.jqueryui.com/w/page/12138135/Widget%20factory], а ещё лучше – заглядывайте в код готовых виджетов "от производителя"
Информация по теме разработки виджетов:
Альтернатива jQuery UI, хотя я бы назвал полезным дополнением. Библиотека jQuery Tools состоит из компонентов, которые разделяются на три типа:
Tabs – аналогично jQuery UI по назначению, скромнее по функционалу, плюс еще есть возможность настраивать как "accordion":
Tooltip – всплывающие подсказки, я не уверен в юзабельности оных, но может для кого-то данный компонент окажется полезным, ведь его так же включили в последний jQuery UI:
Overlay – создание всплывающих модальных окошек, полезный компонент, аля "lightbox":
Scrollable – компонент для создания "карусели" из картинок, может пригодиться в любом онлайн-магазине:
Validator – позволяет на декларативном уровне задавать правила проверки вводимых значений, что бывает очень полезно, и крайне удобно (совместим с HTML5).
RangeInput – аналогичен jQuery UI Slider
DateInput – аналогичен jQuery UI Datepicker
Expose – пожалуй самый замечательный компонент из всего набора – он позволяет выделять элемент на странице, путём затемнение остальных элементов; это трудно описать, лучше посмотрите на демо: http://jquerytools.org/demos/toolbox/expose/index.html
Flashembed – компонент для быстрого и удобного встраивания Flash-объектов на страницу, прямой конкурент SWFObject
Данный набор утилит достаточно долго не обновлялся, с марта 2012-го года, но он ещё не канул в лету, работа идёт, и обещают выпустить вторую версию.
На этом, пожалуй, стоит закончить этот обзор.
jQWidgets – это не просто библиотека, а целый комбайн с кучей полезных виджетов, да их на данный момент насчитывается тридцать четыре штуки, тут только привести список и скриншот на каждый – уже пол книги будет, так что обойдёмся кратеньким резюме на каждый виджет. Начну обзор с комплексных и "тяжёлых" виджетов, к ним картинки я таки приложу.
jqxGrid – это датагрид с кучей полезных и не очень примочек, тут понятное дело есть постраничная навигация, сортировки, фильтрации и группировки, только по этому виджету уже можно здоровенный талмуд написать:
jqxChart – виджет для построения разнообразных графиков с помощью HTML, CSS и JavaScript, сделано всё очень и очень культурно, особенно выделю функцию по сохранению графика как картинки, иногда очень её не хватает:
jqxGauge – этот виджет не часто встретишь и в даже более именитых фреймворках, но по сути – это некий измеритель, т.е. с его помощью можно нарисовать спидометр, манометр, термометр или ещё какой другой измерительный прибор с произвольной шкалой:
jqxTreeMap – ещё один редкий вид, скорее даже уникальный, с его помощью можно построить связанное дерево в виде организованных прямоугольничков, если ничего не понятно, то лучше просмотреть демку, ну и скриншот прилагаю:
jqxTree – это уже не столь экзотический виджет, как понятно из названия, будем садить деревья:
На этом обзор "крутых" виджетов можно заканчивать, углубляться в скучные и обыденный обёртки над элементами форм мне не хочется, замечу лишь, что во многом данный фреймворк обходит jQuery UI, но не всё так радужно в этом королевстве:
Данный фреймворк распространяется под лицензией Creative Commons Attribution-NonCommercial 3.0 License, которая предусматри- вает бесплатное использование библиотеки для не коммерческих проектов, иначе – смотрите расценки.
Ещё стоит упомянуть одну приятную особенность – это возможность легкой интеграции с MVVM фреймворком Knockout, но это уже другая история
А вот это вполне самостоятельный продукт, и как следует из названия предназначен для создания интерфейсов для мобильных устройств с поддержкой "Touch Screen". Этот фреймворк хорошо документирован, с кучей примеров, которые можно пощупать на http://jquerymobile.com/
Данный фреймворк хорошо подходит для создания мобильных версий сайтов, но при этом он будет выглядеть как мобильное приложение, хотя нет – сайт будет выглядеть как сайт на jQuery Mobile. Насколько это хорошо или плохо мне судить сложно, скажем так – это востребовано.
Я не буду рассматривать все компоненты данного фреймворка, приведу лишь некоторые скриншоты (взяты с официального сайта http://jquerymobile.com/):
Для jQMobile существует свой собственный ThemeRoller – http://jquerymobile.com/themeroller/
И еще, посоветую обратить внимание на API данного фреймворка, без изучения оного вам будет затруднительно создать действительно интересные приложения.
Хотелось бы порекомендовать еще несколько плагинов, которые стоит всегда держать под рукой:
color — если потребуется анимация цвета фона, либо шрифта, либо еще чего-нибудь (если не хотите использовать jQuery UI) [https://github.com/jquery/jquery-color]
cookie— удобная работа с "печеньками" в браузере [http://archive.plugins.jquery.com/project/Cookie]
easing — расширяем стандартный набор функций easing (об этом я рассказывал в главе анимация) [http://gsgd.co.uk/sandbox/jquery/easing/]
form — упрощает работу с формами, сам уже давно не пользуюсь, но для быстрого старта самое оно[http://malsup.com/jquery/form/]
hotkeys — название говорит само за себя [https://github.com/jeresig/jquery.hotkeys]
mouswheel — добавляет к jQuery возможность отслеживать события колесика мышки (да, да, из коробки этого функционала нет в библиотеке) [http://brandonaaron.net/code/mousewheel/docs]
profiler – как и следует из названия – помогает отлаживать код jQuery приложений [http://archive.plugins.jquery.com/project/profile] [http://ejohn.org/blog/deep-profiling-jquery-apps/]
shadow animation — как следует из названия – плагин для анимации теней [http://www.bitstorm.org/jquery/shadow-animation/]
jQuery Transition Events – поддержка CSS Transition из JS [https://github.com/ai/transition-events]
SWFObject — если потребуется вставить какую-нибудь flash’ку на страницу, данный плагин облегчит вам участь[http://jquery.thewikies.com/swfobject/]
SWFObject — если потребуется вставить какую-нибудь flash’ку на страницу, данный плагин облегчит вам участь[http://jquery.thewikies.com/swfobject/]
Чем же нам грозит новая версия? Ну нам то боятся её не стоит, а вот пользователи старых версий Internet Explorer не смогут больше насладиться удобством столь популярной библиотеки. Да, да, именно так, из второй версии убрали поддержку IE с 6-ой по 8-ую. Благодаря этой "оптимизации" библиотека похудела на 10%.
Если более современные IE работают в режиме совместимости со старыми версиями, то jQuery не будет заморачиваться, и откажется работать. Избежать это поможет мета-тег X-UA-Compatible или заголовок HTTP.
В скором времени "под нож" пойдут и другие устаревающие браузеры, будьте бдительны Android/WebKit 2.x, за вами уже выехали.
Если вас не зацепила эта диета, то можно пойти дальше, и собрать jQuery только из того, что вам действительно необходимо, что для этого потребуется – читайте в подробном пошаговом руководстве, которому и перевод-то не требуется.
Если вас не впечатляет этот список измений, то это лишь благодаря труду разработчиков jQuery, которые постарались обеспечить полную совместимость API веток 1.х и 2.х, а вот это уже действительно впечатляет.
Ну ладно, не всё так гладко с совместимостью, был этот путь тернист, и проблемы с обновлением будут, вот только искать причину нужно будет в списке изменений версии 1.9, именно эта версия стала поворотной в вопросе совместимости веток.
| 1.0.0 alpha | Первая публикация "для своих", всего 75 скачиваний, вычитка началась |
| 1.0.0 beta | Исправление опечаток и грамматических ошибок. Публикация на Хабре и более 13 000 скачиваний |
| 1.0.0 | Релиз :) Исправлено множество опечаток и несколько ссылок. Добавлена информация о быстродействии селекторов вида "div#id" – спасибо хабрапользователю skorney за тестирование. Более 2 000 скачиваний |
| 1.0.1 | Ещё несколько мелких правок. Спасибо читателям за отзывы. 4500+ |
| 1.0.2 | И ещё… Опубликовал в ePub формате, выложил на scribd, получилось более 8 000 скачиваний и более 10 000 прочтений на scribd |
| 1.0.3 | Обновил книгу вслед за обновлением jQuery, добавил информацию о изменениях в версии 2.х относительно 1.х. Добавил описание виджетов jQWidgets. Удалил описание событий для метода data(). Примеры кода используемые в учебнике теперь доступны на GitHub, так что жду pull-запросов – https://github.com/AntonShevchuk/jquery-for-beginners. Счётчик прочтений на scribd перевалил за 20 тысяч, при этом версию 1.0.2 скачали более 10 тысяч раз… |
| 1.0.4 | Оптимизация шрифтов под печать формата А5. Ушла в тираж. |
| 1.0.5 | Ждёмс… |
Еще чуть-чуть о полезном инструментарии: есть такой классный плагин – jQuery-inlog [http://prinzhorn.github.com/jquery-inlog/] – основное его назначение — дать нам чуть-чуть больше понимания о происходящем внутри самого jQuery, вот кусочек HTML:
<body> <div class="bar"> <div class="bar"> <div id="foo"></div> </div> </div> <div id="bacon"></div> </body>
А вот и код, который его обслуживает:
$l(true);
$("#foo").parents(".bar").next().prev().parent().fadeOut();
$l(false);
Какие-то странные манипуляции, для какого же элемента будет применён метод "fadeout()"? Для выяснения оного наш код обёрнут в вызов метода "$l()". "$l()" — это и есть собственно вызов плагина, результат его работы можно найти в консоли:
У данного плагина есть ещё настройки, которые регулируют объём информации выводимой в консоль.
Пример и скриншот взять с официальной документации по плагину
jQuery UI представляет из себя набор виджетов и плагинов от самих разработчиков jQuery. По моему мнению, данный инструмент необходимо изучить настолько, насколько это требуется чтобы не писать свои "велосипеды". Скачать-почитать о данной надстройке над jQuery можно на домашней страницы проекта – http://jqueryui.com/
Что нам необходимо знать о виджетах и плагинах? Первое – это какие они есть, и второе – как работают. На этих двух моментах я и постараюсь остановиться.
Начну с полезных плагинов, которые могут упростить жизнь при создании интерактивных интерфейсов:
Виджеты – это уже комплексное решение содержащие не только JavaScript код, но и некую HTML и CSS реализацию:
<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Accordion</title>
<link rel="profile" href="http://gmpg.org/xfn/11"/>
<link rel="shortcut icon" href="http://anton.shevchuk.name/favicon.ico"/>
<link rel="stylesheet" href="css/styles.css"/>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/code.js"></script>
<script type="text/javascript">
$(function(){
var toDisplay = 1;
$("article h2").click(function(){
var $this = $(this);
$this
.next("p")
.slideToggle("slow")
.siblings("p:visible")
.slideUp("slow");
$this.toggleClass("active");
$this.siblings("h2").removeClass("active");
})
.eq(toDisplay).addClass("active")
.next().show();
});
</script>
<style type="text/css">
article h2 {
background: #e9e7e7 url(images/arrows.png) no-repeat 618px 7px;
padding: 7px 15px;
margin: 0;
border: solid 1px #c4c4c4;
border-bottom: none;
cursor: pointer;
}
article h2:hover {
background-color: #e3e2e2;
}
article h2.active {
background-position: 618px -23px;
}
article p {
display: none;
margin: 0;
padding: 10px 15px 20px;
}
</style>
</head>
<body>
<div id="content" class="wrapper box">
<menu>
<a href="index.html" title="go prev" class="button alignleft" rel="prev">← Back </a>
<a href="index.html" title="back to Index" class="button alignleft" rel="index">Index §</a>
<a href="#" title="reload" class="button alignleft" onclick="window.location.reload();return false">Reload ¤</a>
<a href="tabs.html" title="go next" class="button alignright" rel="next">Next →</a>
</menu>
<header>
<h1>Реализация аккордиона</h1>
<h2>На jQuery без использования jQuery UI</h2>
</header>
<article>
<h2>Article Title</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus rutrum,
lectus eu varius consectetur, libero velit hendrerit augue, ut posuere enim neque
in libero. Donec eget sagittis nibh. Suspendisse sed tincidunt urna. Cras quis
euismod neque. Maecenas auctor ultricies posuere. Pellentesque luctus pulvinar dui
eget semper. Donec sodales odio eu sapien varius luctus. Donec dictum feugiat diam
at malesuada. Sed nec massa in augue condimentum faucibus quis ut diam. Quisque
nisl sem, semper nec vulputate vel, mattis sit amet justo. Aliquam purus felis,
tempor at scelerisque quis, tincidunt in neque. Etiam ut risus diam. Pellentesque
fermentum risus id elit feugiat cursus. Ut fringilla dictum diam, sed iaculis
lorem pulvinar ut. Cras vel elit id velit commodo viverra sit amet vel orci.</p>
<h2>Article Title</h2>
<p>Duis in vestibulum sem. Cras euismod tincidunt dui, et scelerisque tellus condimentum vel.
Maecenas et urna sit amet risus fermentum rhoncus nec porttitor ligula. Maecenas sit amet
turpis enim, ut iaculis est. Duis feugiat, lacus id placerat porttitor, lorem augue gravida
nisi, eu porta eros risus et lectus. Maecenas vestibulum nunc vel ipsum tincidunt sit amet
blandit sapien bibendum. Proin vel vulputate nisl. Duis tempor imperdiet placerat. Pellentesque
faucibus consequat magna, et bibendum nisl egestas non. Pellentesque sit amet mattis augue.
Aenean at diam tincidunt purus sollicitudin gravida non in nisi. Fusce bibendum, magna in
adipiscing mattis, sem risus fringilla mi, nec gravida lectus lectus at nibh. Suspendisse
adipiscing elementum laoreet. Suspendisse sem erat, varius quis aliquet vitae, dapibus sed
nibh. Nullam iaculis sem at mauris faucibus in vestibulum libero pretium. Aliquam eu turpis
libero. Fusce et ultrices lectus.</p>
<h2>Article Title</h2>
<p>Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
Morbi dapibus, dui in consequat pulvinar, nunc erat consequat ipsum, ut blandit nulla eros ac purus.
In at justo sed lorem consequat fermentum. Nunc scelerisque purus sed neque rutrum adipiscing. Sed
vehicula tristique dolor, quis porttitor magna dictum eu. Cras tristique erat non orci aliquam tempor.
In hac habitasse platea dictumst. Nam eget sodales neque. Aenean adipiscing consequat diam, eu
molestie diam dictum eu.</p>
</article>
<footer>
©copyright 2014 Anton Shevchuk — <a href="http://anton.shevchuk.name/jquery-book/">jQuery Book</a>
</footer>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1669896-2']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</body>
</html>

<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tabs</title>
<link rel="profile" href="http://gmpg.org/xfn/11"/>
<link rel="shortcut icon" href="http://anton.shevchuk.name/favicon.ico"/>
<link rel="stylesheet" href="css/styles.css"/>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/code.js"></script>
<script type="text/javascript">
$(function(){
var hash = window.location.hash;
$("article li a").click(function(){
var $this = $(this);
var $pan = $("article").find($this.attr('href'));
if (!$this.hasClass('active')) {
$("article li a").removeClass("active");
$("article p").hide();
$this.addClass("active");
$pan.show();
window.location.hash = $this.attr('href');
}
return false;
});
if (hash $("article li a[href="+hash+"]").length) {
$("article li a[href="+hash+"]").click();
} else {
$("article li a").eq(0).click();
}
});
</script>
<style type="text/css">
article ul {
padding: 0 15px 0;
margin-bottom: -1px;
overflow: hidden;
}
article li {
float:left;
list-style: none;
margin: 0 4px;
}
article li a {
display: block;
padding: 4px 8px;
background: #f5f5f5;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 2px 2px 0 0;
}
article p {
clear: both;
display: none;
margin: 0 4px;
padding: 10px 15px 20px;
border: 1px solid #ccc;
border-radius: 2px;
}
article a.active {
background: #fff;
border-bottom: 1px solid #fff;
}
</style>
</head>
<body>
<div id="content" class="wrapper box">
<menu>
<a href="accordion.html" title="go prev" class="button alignleft" rel="prev">← Prev </a>
<a href="index.html" title="back to Index" class="button alignleft" rel="index">Index §</a>
<a href="#" title="reload" class="button alignleft" onclick="window.location.reload();return false">Reload ¤</a>
<a href="widget.html" title="go next" class="button alignright" rel="next">Next →</a>
</menu>
<header>
<h1>Реализация закладок</h1>
<h2>На jQuery без использования jQuery UI</h2>
</header>
<article>
<ul>
<li><a href="#pan1">First Article</a></li>
<li><a href="#pan2">Second Article</a></li>
<li><a href="#pan3">Third Article</a></li>
</ul>
<p id="pan1">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus rutrum,
lectus eu varius consectetur, libero velit hendrerit augue, ut posuere enim neque
in libero. Donec eget sagittis nibh. Suspendisse sed tincidunt urna. Cras quis
euismod neque. Maecenas auctor ultricies posuere. Pellentesque luctus pulvinar dui
eget semper. Donec sodales odio eu sapien varius luctus. Donec dictum feugiat diam
at malesuada. Sed nec massa in augue condimentum faucibus quis ut diam. Quisque
nisl sem, semper nec vulputate vel, mattis sit amet justo. Aliquam purus felis,
tempor at scelerisque quis, tincidunt in neque. Etiam ut risus diam. Pellentesque
fermentum risus id elit feugiat cursus. Ut fringilla dictum diam, sed iaculis
lorem pulvinar ut. Cras vel elit id velit commodo viverra sit amet vel orci.</p>
<p id="pan2">Duis in vestibulum sem. Cras euismod tincidunt dui, et scelerisque tellus condimentum vel.
Maecenas et urna sit amet risus fermentum rhoncus nec porttitor ligula. Maecenas sit amet
turpis enim, ut iaculis est. Duis feugiat, lacus id placerat porttitor, lorem augue gravida
nisi, eu porta eros risus et lectus. Maecenas vestibulum nunc vel ipsum tincidunt sit amet
blandit sapien bibendum. Proin vel vulputate nisl. Duis tempor imperdiet placerat. Pellentesque
faucibus consequat magna, et bibendum nisl egestas non. Pellentesque sit amet mattis augue.
Aenean at diam tincidunt purus sollicitudin gravida non in nisi. Fusce bibendum, magna in
adipiscing mattis, sem risus fringilla mi, nec gravida lectus lectus at nibh. Suspendisse
adipiscing elementum laoreet. Suspendisse sem erat, varius quis aliquet vitae, dapibus sed
nibh. Nullam iaculis sem at mauris faucibus in vestibulum libero pretium. Aliquam eu turpis
libero. Fusce et ultrices lectus.</p>
<p id="pan3">Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
Morbi dapibus, dui in consequat pulvinar, nunc erat consequat ipsum, ut blandit nulla eros ac purus.
In at justo sed lorem consequat fermentum. Nunc scelerisque purus sed neque rutrum adipiscing. Sed
vehicula tristique dolor, quis porttitor magna dictum eu. Cras tristique erat non orci aliquam tempor.
In hac habitasse platea dictumst. Nam eget sodales neque. Aenean adipiscing consequat diam, eu
molestie diam dictum eu.</p>
</article>
<footer>
©copyright 2014 Anton Shevchuk — <a href="http://anton.shevchuk.name/jquery-book/">jQuery Book</a>
</footer>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1669896-2']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</body>
</html>
На этом обзор виджетов можно считать законченным, вернёмся к плагинам.
Все виджеты и плагины завязаны на ядро jQuery UI, но есть так же зависимости между самими плагинами и стоит о них помнить. Но не переживайте – при сборке jQuery UI пакета все зависимости проверяются автоматически, т.е. когда вам потребуется доселе неподключенный виджет, лучше скачать сборку заново.
Утилит у нас не много – вот полезный плагин – position, который позволяет контролировать положение DOM элементов – http://jqueryui.com/position/, а ещё есть фабрика по созданию виджетов, но о ней я расскажу чуть попозже.
Среди эффектов предоставляемых jQuery UI я выделяю четыре пункта:
За анимацию цвета отвечает компонент "Effects Core", который позволяет анимировать изменения цвета посредством использования функции "animate()":
$("#my").animate({ backgroundColor: "black" }, 1000);
Да-да, jQuery из коробки не умеет этого делать, а вот jQuery UI позволяет анимировать следующие параметры:
Ещё одной возможностью заключенной в "Effects Core" является анимация изменений класса DOM элемента, т.е. когда вы будете присваивать новый класс элементу, то вместо обычного моментального применения новых CSS свойств вы будете наблюдать анимацию этих свойств от текущих до заданных в присваиваемом классе. Для использования данного функционала нам потребуются старые знакомые – методы "addClass()", "toggleClass()" и "removeClass()", с одной лишь разницей – при вызове метода вторым параметром должна быть указана скорость анимации:
$("#my").addClass("active", 1000);
$("#my").toggleClass("active", 1000);
$("#my").removeClass("active", 1000);
Если из предыдущего абзаца у вас не возникло понимания сути происходящего, то этот код для вас:
<style>
#my {
font-size:14px;
}
#my.active {
font-size:20px;
}
</style>
<script>
$(function (){
$("#my").addClass("active", 1000);
// тут получается аналогично следующему вызову
$("#my").animate({"font-size":"20px"}, 1000);
});
</script>
А ещё появляется метод switchClass(removeClass, addClass, duration), который заменяет один класс другим, но мне он ни разу не пригодился.
О наборе эффектов я не буду долго рассказывать, их лучше посмотреть в действии на странице http://jqueryui.com/effect/. Для работы с эффектами появляется метод "effect()", но сам по себе его лучше не использовать, ведь UI расширил функционал встроенных методов "show()", "hide()" и "toggle()", теперь, передав в качестве параметра скорости анимации названия эффекта вы получите необходимый результат:
$("#my").hide("puff");
$("#my").show("transfer");
$("#my").toggle("explode");
Приведу список эффектов, может кто запомнит: blind, bounce, clip, drop, explode, fold, highlight, puff, pulsate, scale, shake, size, slide, transfer.
Помните, я в главе о анимации рассказывал о easing и одноименном плагине для jQuery? Так вот UI тоже расширяет easing, так что подключив его можно отключать плагин. И да, этот функционал завязан лишь на "Effects Core".
Одной из самых замечательных особенностей jQuery UI является возможность менять "шкурки" всех виджетов разом, и для этого даже предусмотрена специальная утилита – ThemeRoller [http://jqueryui.com/themeroller/]:
Если в какой-то момент времени потребуется внести изменения в тему, то откройте файл jquery-ui-#.#.##-custom.css и найдёте строчку начинающуюся с текста "To view and modify this theme, visit http://..." и таки пройдите по указанной ссылке, и уже используя ThemeRoller внесите необходимые изменения.
Отправной точкой при написания виджета для jQuery UI для вас будет официальная документация, но поскольку со знанием английского не у всех сложилось, то я постараюсь перевести и адаптировать информацию изложенную в ней.
Первое, о чём стоит рассказать, это то, что правила написания плагинов для jQuery слишком вальяжны, что не способствует их качеству. При создании jQuery UI, походу, решили пойти путём стандартизации процесса написания плагинов и виджетов, я не могу сказать насколько задумка удалась, но стало явно лучше чем было. Начну с описания каркаса для вашего виджета:
$.widget("book.expose", {
// настройки по умолчанию
options: {
color: "red"
},
// инициализация widget
// вносим изменения в DOM и вешаем обработчики
_create: function() {
this.element; // искомый объект в jQuery обёртке
this.name; // имя - expose
this.namespace; // пространство – book
this.element.on("click."+this.eventNamespace, function(){
console.log("click");
})
},
// метод отвечает за применение настроек
_setOption: function( key, value ) {
// применяем изменения настроек
this._super("_setOption", key, value );
},
// метод _destroy должен быть антиподом к _create
// он должен убрать все изменения внесенные изменения в DOM
// и убрать все обработчики, если таковые были
_destroy: function() {
this.element.unbind('.'+this.eventNamespace);
}
});
Поясню для тех кто не прочёл комментарии:
options – хранилище настроек виджета для конкретного элемента_create() – отвечает за инициализацию виджета – тут должны
происходить изменения в DOM'е, и "вешаться" обработчики событий_destroy() – антипод для "_create()" – должен подчистить всё, что мы
намусорили_setOption(key, value) – данный метод будет вызван при попытке
изменить какие-либо настройки:$("#my").expose({key:value})
Наблюдательный глаз заметит, что все перечисленные методы начинаются со знака подчёркивания – это такой способ выделить "приватные" методы, которые недоступны для запуска, и если мы попытаемся запустить "$('#my').expose('_destroy')", то получим ошибку. Но учтите – это лишь договорённость, соблюдайте, её!
Для обхода договорённости о приватности можно использовать метод "data()":
$("#my").data("expose")._destroy() // место для смайла "(evil)"
В данном примере, я постарался задать хороший тон написания виджетов – я "повесил" обработчики событий в namespace, это даст в дальнейшем возможность контролировать происходящее без необходимости залазить в код виджета, это "true story".
Код описанный в методе "_destroy()" – избыточен, т.к. он и так выполняется в публичном "destroy()", приведён тут для наглядности.
А для ленивых, чтобы не прописывать каждый раз "eventNamespace" в обработчиках событий, разработчики добавили в версии 1.9.0 два метода: "_on()" и "_off()", первый принимает два параметра:
Все перечисленные события будут "висеть" в пространстве "eventNamespace", т.е. результат будет предположительно одинаковым:
this._on(this.element, {
mouseover:function(event) {
console.log("Hello mouse");
},
mouseout:function(event) {
console.log("Bye mouse");
}
});
Второй метод – "_off()" – позволяет выборочно отключать обработчики:
this._off(this.element, "mouseout click");
Ну каркас баркасом, пора переходить к функционалу – добавим произвольную функцию с произвольным функционалом:
callMe:function(){
console.log("Allo?");
}
К данной функции мы легко сможем обращаться как из других методов виджета так и извне:
// изнутри
this.callMe()
// извне
$("#my").expose("callMe")
Если ваша функция принимает параметры, то передача оных осуществляется следующим способом:
$("#my").expose("callMe", "Hello!")
Если вы хотите достучаться в обработчике событий до метода виджета, то не забудьте про область видимости переменных, и сделайте следующий манёвр:
_create: function() {
var self = this; // вот он!
this.element.on("click."+this.eventNamespace, function(){
// тут используем self, т.к. this уже указывает на
// элемент по которому кликаем
self.callMe();
})
},
Хорошо идём, теперь поговорим о событиях – для более гибкой разработки и внедрения виджетов предусмотрен функционал по созданию произвольных событий и их "прослушиванию":
// инициируем событие
this._trigger("incomingCall");
// подписываемся на событие при инициализации виджета
$("#my").expose({
incommingCall: function(ev) {
console.log("din-don");
}
})
// или после, используя в качестве имени события
// имя виджета + имя события
$("#my").bind("exposeincomingCall", function(){
console.log("tru-lya-lya")
});
Материала много, я понимаю, но ещё добавлю описание нескольких методов которые можно вызвать из самого виджета:
_delay() – данная функция работает как "setTimeout()", вот только
контекст переданной функции будет указывать на сам виджет (это чтобы
не заморачиваться с областью видимости)
_hoverable() и _focusable() – данным методам необходимо скармливать
элементы для которых необходимо отслеживать события "hover" и
"focus", чтобы автоматически добавит к ним классы "ui-state-hover" и
"ui-state-focus" при наступлении оных
_hide() и _show() – эти два метода появились в версии 1.9.0, они созданы
дабы стандартизировать поведение виджетов при использовании
методов анимации, настройки принято прятать в опциях под ключами
"hide" и "show" соответственно. Использовать методы следует
следующим образом:
options: {
hide: {
effect: "slideDown", // настройки эквиваленты вызову
duration: 500 // .slideDown( 500)
}
}
// внутри виджета следует использовать вызовы _hide() и _show()
this._hide( this.element, this.options.hide, function() {
// это наша функция обратного вызова
console.log('спрятали');
});
Существует ещё пару методов, которые реализованы за нас:
enable: function() {
return this._setOption( "disabled", false );
},
disable: function() {
return this._setOption( "disabled", true );
},
Фактически, данный функции создают синоним для вызова:
$("#my").expose({ "disabled": true }) // или false
Наша задача сводится лишь к отслеживанию данного флага в методе "_setOption()".
Примеру быть, возможно этот виджет и не будет популярен, зато он наглядно демонстрирует как создавать виджеты для jQuery UI.
<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Пример widget'а для jQuery UI</title>
<link rel="profile" href="http://gmpg.org/xfn/11"/>
<link rel="shortcut icon" href="http://anton.shevchuk.name/favicon.ico"/>
<link rel="stylesheet" href="css/styles.css"/>
<style>
.expose-widget {
position: absolute;
z-index: 999;
background-color: rgba(0, 0, 0, 0.42);
display: none;
}
</style>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/jquery-ui.js"></script>
<script type="text/javascript" src="js/code.js"></script>
<script>
(function( $, undefined ) {
$.widget( "book.expose", {
version: "1.0.0",
// наши настройки
options: {
color: null, // цвет фона
speed: 500, // скорость анимации
show: 500, // настройки для метода _show()
hide: { // настройки для метода _hide()
effect: "fade",
duration: 500
}
},
// инициализация
_create: function() {
var self = this;
// выбранному элементу добавляем наш класс
// и вешаем обработчик события "клик"
this.element
.addClass( "book-widget" )
.on('click.expose-widget.'+this.eventNamespace, function() {
// вызываем метод виджета
// виджет доступен в переменной self
if (self.element.data('expose-it')) {
self.unmask();
} else {
self.mask();
}
return false;
});
// нам необходимо инициировать окружение лишь один раз для всех элементов
// это наш флаг
var totalInited = $.data(document.body, 'expose');
if (!totalInited) {
// изменяем флаг - у нас уже запущена инициализация
$.data(document.body, 'expose', 1);
// инициализация верхнего "бокса"
// и добавление в DOM
var $topBox = $('<div></div>');
$topBox.addClass("expose-widget");
$topBox.appendTo(document.body);
// сохраняем на него ссылку в реестре
$.data(document.body, 'topBox', $topBox);
// клонируем верхний бокс
// добавляем и сохраняем
var $bottomBox = $topBox.clone();
$bottomBox.appendTo(document.body);
$.data(document.body, 'bottomBox', $bottomBox);
// повторяем для левого
var $leftBox = $topBox.clone();
$leftBox.appendTo(document.body);
$.data(document.body, 'leftBox', $leftBox);
// и для правого
var $rightBox = $topBox.clone();
$rightBox.appendTo(document.body);
$.data(document.body, 'rightBox', $rightBox);
// все боксы разом
$allBox = $topBox.add($bottomBox).add($leftBox).add($rightBox);
$.data(document.body, 'allBox', $allBox);
// вешаем единый обработчик события для всех боксов
$(document.body).on('click.expose-widget', '.expose-widget', function() {
// вызов метода виджета
self.unmask();
return false;
});
// кидаем событие, на него можно подписаться лишь при инициализации виджета
// иначе толку не будет - будет поздно
this._trigger('build');
} else {
// отслеживаем кол-во виджетов
totalInited++;
$.data(document.body, 'expose', totalInited);
}
// вызываем метод виджета для применения цвета
this._setCurrentColor();
},
// ломаем всё что строили
_destroy: function() {
// подчищаем наш элемент
this.element
.removeClass( "book-widget" )
// данный метод избыточен, т.к. это делает за нас публичный метод destroy()
.off('.'+this.eventNamespace);
// декрементим кол-во инициализированных виджетов
var totalInited = $.data(document.body, 'expose');
totalInited--;
$.data(document.body, 'expose', totalInited);
// если больше нет виджетов
// удаляем вспомогательные боксы
if (totalInited==0) {
$.data(document.body, 'allBox').remove();
$(document.body).off('.expose-widget');
this._trigger('destroy');
}
},
// применяем настройки
_setOption: function( key, value ) {
if (key == 'disabled') {
// тут должен быть код по отключению виджета
}
if (key == 'speed') {
this.options.show = value;
this.options.hide.duration = value;
}
this._super( key, value );
},
// применяем настройки цвета
_setCurrentColor: function() {
this.options.color = $.data(document.body, 'topBox').css('background-color');
},
// изменяем цвет
color: function(value) {
$.data(document.body, 'allBox').css('background-color', value);
this._setCurrentColor();
},
// прячем боксы
unmask: function() {
var self = this;
// получаем набор
var $allBox = $.data(document.body, 'allBox');
// вызываем функцию анимации
this._hide($allBox, this.options.hide, function() {
// бросаем событие по завершению
self._trigger('unmask')
});
this._resetFlag();
// изменяем флаг
this.element.data('expose-it', false);
},
// показываем боксы
mask: function() {
var self = this;
// берём все "боксы"
var $allBox = $.data(document.body, 'allBox');
var $topBox = $.data(document.body, 'topBox');
var $bottomBox = $.data(document.body, 'bottomBox');
var $leftBox = $.data(document.body, 'leftBox');
var $rightBox = $.data(document.body, 'rightBox');
// вычисляем текущие координаты элемента и размеры окна
var offset = this.element.offset();
var height = this.element.outerHeight();
var width = this.element.outerWidth();
var winWidth = $(document).width();
var winHeight = $(document).height();
var topSettings = {
top:0,
left:0,
width:winWidth,
height:offset.top,
backgroundColor:this.options.color
};
var leftSettings = {
top:offset.top,
left:0,
width:offset.left,
height:height,
backgroundColor:this.options.color
};
var rightSettings = {
top:offset.top,
left:offset.left+width,
width:winWidth - (offset.left+width),
height:height,
backgroundColor:this.options.color
};
var bottomSettings = {
top:offset.top+height,
left:0,
width:winWidth,
height:winHeight - (offset.top+height),
backgroundColor:this.options.color
};
// проверяем - отображается у нас боксы в данный момент времени или нет
if ($topBox.is(':hidden')) {
// применяем настройки
$topBox.css(topSettings);
$leftBox.css(leftSettings);
$rightBox.css(rightSettings);
$bottomBox.css(bottomSettings);
// показываем все наши боксы
this._show( $allBox, this.options.show, function() {
// событие mask
self._trigger('mask');
});
} else {
this._resetFlag();
// применяем настройки через анимацию
$topBox.animate(topSettings, this.options.speed);
$leftBox.animate(leftSettings, this.options.speed);
$rightBox.animate(rightSettings, this.options.speed);
$bottomBox.animate(bottomSettings, this.options.speed, function(){
// событие mask
self._trigger('mask');
});
}
// изменяем флаг
this.element.data('expose-it', true);
},
_resetFlag:function() {
// workaround - надо "сбросить" флаг для всех других элементов
// надо будет придумать более красивое решение
$.each($.cache, function(i, el) {
if (el.data != undefined el.data.exposeIt != undefined) {
el.data.exposeIt = false;
}
});
}
});
})( jQuery );
</script>
</head>
<body>
<div id="content" class="wrapper box">
<menu label="Try...">
<a href="tabs.html" title="go prev" class="button alignleft" rel="prev">← Prev </a>
<a href="index.html" title="back to Index" class="button alignleft" rel="index">Index §</a>
<a href="#" title="reload" class="button alignleft" onclick="window.location.reload();return false">Reload ¤</a>
<hr/>
<pre><code><em>// run widget and try to click on article</em>
$(<span>'article'</span>).expose()</code></pre>
<button type="button" class="code">Run Code</button>
<pre><code contenteditable="true"><em>// configuration was changed</em>
$(<span>'article'</span>).expose({speed:2000})</code></pre>
<button type="button" class="code">Run Code</button>
<pre><code contenteditable="true"><em>// run widget and try to click on image</em>
$(<span>'article img'</span>).expose({speed:100})</code></pre>
<button type="button" class="code">Run Code</button>
<pre><code><em>// try widget API - trigger</em>
$(<span>'article:eq(0)'</span>).bind(<span>'exposemask'</span>,
function(){
$(this).css(<span>'color'</span>, <span>'red'</span>);
});
$(<span>'article:eq(0)'</span>).bind(<span>'exposeunmask'</span>,
function(){
$(this).css(<span>'color'</span>, <span>'black'</span>);
})</code></pre>
<button type="button" class="code">Run Code</button>
<pre><code><em>// try widget API - call method</em>
$(<span>'article:eq(1)'</span>).expose(<span>'mask'</span>)</code></pre>
<button type="button" class="code">Run Code</button>
<pre><code contenteditable="true"><em>// try widget API - call method+args</em>
$(<span>'article:eq(1)'</span>).expose(
<span>'color'</span>,
<span>'rgba(255, 0, 0, 0.5)'</span>
)</code></pre>
<button type="button" class="code">Run Code</button>
</menu>
<header>
<h1>widget</h1>
<h2>Пишем своё виджет для jQuery UI</h2>
</header>
<article>
<h2>Article</h2>
<p>
<img src="images/photo-bumblebee-tumb.jpg" alt="Bumblebee" class="left" width="200"/>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus rutrum,
lectus eu varius consectetur, libero velit hendrerit augue, ut posuere enim neque
in libero. Donec eget sagittis nibh. Suspendisse sed tincidunt urna. Cras quis
euismod neque. Maecenas auctor ultricies posuere. Pellentesque luctus pulvinar dui
eget semper. Donec sodales odio eu sapien varius luctus. Donec dictum feugiat diam
at malesuada. Sed nec massa in augue condimentum faucibus quis ut diam. Quisque
nisl sem, semper nec vulputate vel, mattis sit amet justo. Aliquam purus felis,
tempor at scelerisque quis, tincidunt in neque. Etiam ut risus diam. Pellentesque
fermentum risus id elit feugiat cursus. Ut fringilla dictum diam, sed iaculis
lorem pulvinar ut. Cras vel elit id velit commodo viverra sit amet vel orci.</p>
</article>
<article>
<h2>Article</h2>
<p>
<img src="images/photo-chamomile-tumb.jpg" alt="Chamomile" class="left" width="200"/>
Duis in vestibulum sem. Cras euismod tincidunt dui, et scelerisque tellus condimentum vel.
Maecenas et urna sit amet risus fermentum rhoncus nec porttitor ligula. Maecenas sit amet
turpis enim, ut iaculis est. Duis feugiat, lacus id placerat porttitor, lorem augue gravida
nisi, eu porta eros risus et lectus. Maecenas vestibulum nunc vel ipsum tincidunt sit amet
blandit sapien bibendum. Proin vel vulputate nisl. Duis tempor imperdiet placerat. Pellentesque
faucibus consequat magna, et bibendum nisl egestas non. Pellentesque sit amet mattis augue.
Aenean at diam tincidunt purus sollicitudin gravida non in nisi. Fusce bibendum, magna in
adipiscing mattis, sem risus fringilla mi, nec gravida lectus lectus at nibh. Suspendisse
adipiscing elementum laoreet. Suspendisse sem erat, varius quis aliquet vitae, dapibus sed
nibh. Nullam iaculis sem at mauris faucibus in vestibulum libero pretium. Aliquam eu turpis
libero. Fusce et ultrices lectus.</p>
</article>
<article>
<h2>Article</h2>
<p>
<img src="images/photo-maple-leaf-tumb.jpg" alt="Maple Leaf" class="left" width="200"/>
Ut consequat commodo mauris, eu dignissim justo congue vel. Etiam commodo tincidunt diam,
laoreet ullamcorper sapien egestas quis. Etiam auctor rutrum ante, at tincidunt elit lacinia
non. Pellentesque molestie tellus sit amet est sodales nec rutrum leo pharetra. Donec lacinia
ipsum vitae massa accumsan ullamcorper. Maecenas commodo lacus turpis. Proin sit amet mauris
sem, imperdiet faucibus lorem. Fusce ullamcorper consectetur ligula vel pretium. Sed et elit
vitae orci adipiscing condimentum id sed turpis. Morbi ultrices feugiat ullamcorper. Fusce at
magna dolor. Sed sit amet risus massa, quis imperdiet libero. Proin justo purus, sodales nec
cursus et, sollicitudin at nulla. Vivamus eget nibh tellus, sit amet facilisis ante.</p>
</article>
<footer>
©copyright 2014 Anton Shevchuk — <a href="http://anton.shevchuk.name/jquery-book/">jQuery Book</a>
</footer>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1669896-2']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</body>
</html>
Будьте внимательны, с выходом jQuery UI версии 1.9.0 были внесены правки в Widget API, следовательно, большинство доступной инфор- мации устарело, так что читайте официальную документацию [http://wiki.jqueryui.com/w/page/12138135/Widget%20factory], а ещё лучше – заглядывайте в код готовых виджетов "от производителя"
Информация по теме разработки виджетов:
Альтернатива jQuery UI, хотя я бы назвал полезным дополнением. Библиотека jQuery Tools состоит из компонентов, которые разделяются на три типа:
Tabs – аналогично jQuery UI по назначению, скромнее по функционалу, плюс еще есть возможность настраивать как "accordion":
Tooltip – всплывающие подсказки, я не уверен в юзабельности оных, но может для кого-то данный компонент окажется полезным, ведь его так же включили в последний jQuery UI:
Overlay – создание всплывающих модальных окошек, полезный компонент, аля "lightbox":
Scrollable – компонент для создания "карусели" из картинок, может пригодиться в любом онлайн-магазине:
Validator – позволяет на декларативном уровне задавать правила проверки вводимых значений, что бывает очень полезно, и крайне удобно (совместим с HTML5).
RangeInput – аналогичен jQuery UI Slider
DateInput – аналогичен jQuery UI Datepicker
Expose – пожалуй самый замечательный компонент из всего набора – он позволяет выделять элемент на странице, путём затемнение остальных элементов; это трудно описать, лучше посмотрите на демо: http://jquerytools.org/demos/toolbox/expose/index.html
Flashembed – компонент для быстрого и удобного встраивания Flash-объектов на страницу, прямой конкурент SWFObject
Данный набор утилит достаточно долго не обновлялся, с марта 2012-го года, но он ещё не канул в лету, работа идёт, и обещают выпустить вторую версию.
На этом, пожалуй, стоит закончить этот обзор.
jQWidgets – это не просто библиотека, а целый комбайн с кучей полезных виджетов, да их на данный момент насчитывается тридцать четыре штуки, тут только привести список и скриншот на каждый – уже пол книги будет, так что обойдёмся кратеньким резюме на каждый виджет. Начну обзор с комплексных и "тяжёлых" виджетов, к ним картинки я таки приложу.
jqxGrid – это датагрид с кучей полезных и не очень примочек, тут понятное дело есть постраничная навигация, сортировки, фильтрации и группировки, только по этому виджету уже можно здоровенный талмуд написать:
jqxChart – виджет для построения разнообразных графиков с помощью HTML, CSS и JavaScript, сделано всё очень и очень культурно, особенно выделю функцию по сохранению графика как картинки, иногда очень её не хватает:
jqxGauge – этот виджет не часто встретишь и в даже более именитых фреймворках, но по сути – это некий измеритель, т.е. с его помощью можно нарисовать спидометр, манометр, термометр или ещё какой другой измерительный прибор с произвольной шкалой:
jqxTreeMap – ещё один редкий вид, скорее даже уникальный, с его помощью можно построить связанное дерево в виде организованных прямоугольничков, если ничего не понятно, то лучше просмотреть демку, ну и скриншот прилагаю:
jqxTree – это уже не столь экзотический виджет, как понятно из названия, будем садить деревья:
На этом обзор "крутых" виджетов можно заканчивать, углубляться в скучные и обыденный обёртки над элементами форм мне не хочется, замечу лишь, что во многом данный фреймворк обходит jQuery UI, но не всё так радужно в этом королевстве:
Данный фреймворк распространяется под лицензией Creative Commons Attribution-NonCommercial 3.0 License, которая предусматри- вает бесплатное использование библиотеки для не коммерческих проектов, иначе – смотрите расценки.
Ещё стоит упомянуть одну приятную особенность – это возможность легкой интеграции с MVVM фреймворком Knockout, но это уже другая история
А вот это вполне самостоятельный продукт, и как следует из названия предназначен для создания интерфейсов для мобильных устройств с поддержкой "Touch Screen". Этот фреймворк хорошо документирован, с кучей примеров, которые можно пощупать на http://jquerymobile.com/
Данный фреймворк хорошо подходит для создания мобильных версий сайтов, но при этом он будет выглядеть как мобильное приложение, хотя нет – сайт будет выглядеть как сайт на jQuery Mobile. Насколько это хорошо или плохо мне судить сложно, скажем так – это востребовано.
Я не буду рассматривать все компоненты данного фреймворка, приведу лишь некоторые скриншоты (взяты с официального сайта http://jquerymobile.com/):
Для jQMobile существует свой собственный ThemeRoller – http://jquerymobile.com/themeroller/
И еще, посоветую обратить внимание на API данного фреймворка, без изучения оного вам будет затруднительно создать действительно интересные приложения.
Хотелось бы порекомендовать еще несколько плагинов, которые стоит всегда держать под рукой:
color — если потребуется анимация цвета фона, либо шрифта, либо еще чего-нибудь (если не хотите использовать jQuery UI) [https://github.com/jquery/jquery-color]
cookie— удобная работа с "печеньками" в браузере [http://archive.plugins.jquery.com/project/Cookie]
easing — расширяем стандартный набор функций easing (об этом я рассказывал в главе анимация) [http://gsgd.co.uk/sandbox/jquery/easing/]
form — упрощает работу с формами, сам уже давно не пользуюсь, но для быстрого старта самое оно[http://malsup.com/jquery/form/]
hotkeys — название говорит само за себя [https://github.com/jeresig/jquery.hotkeys]
mouswheel — добавляет к jQuery возможность отслеживать события колесика мышки (да, да, из коробки этого функционала нет в библиотеке) [http://brandonaaron.net/code/mousewheel/docs]
profiler – как и следует из названия – помогает отлаживать код jQuery приложений [http://archive.plugins.jquery.com/project/profile] [http://ejohn.org/blog/deep-profiling-jquery-apps/]
shadow animation — как следует из названия – плагин для анимации теней [http://www.bitstorm.org/jquery/shadow-animation/]
jQuery Transition Events – поддержка CSS Transition из JS [https://github.com/ai/transition-events]
SWFObject — если потребуется вставить какую-нибудь flash’ку на страницу, данный плагин облегчит вам участь[http://jquery.thewikies.com/swfobject/]
SWFObject — если потребуется вставить какую-нибудь flash’ку на страницу, данный плагин облегчит вам участь[http://jquery.thewikies.com/swfobject/]
Чем же нам грозит новая версия? Ну нам то боятся её не стоит, а вот пользователи старых версий Internet Explorer не смогут больше насладиться удобством столь популярной библиотеки. Да, да, именно так, из второй версии убрали поддержку IE с 6-ой по 8-ую. Благодаря этой "оптимизации" библиотека похудела на 10%.
Если более современные IE работают в режиме совместимости со старыми версиями, то jQuery не будет заморачиваться, и откажется работать. Избежать это поможет мета-тег X-UA-Compatible или заголовок HTTP.
В скором времени "под нож" пойдут и другие устаревающие браузеры, будьте бдительны Android/WebKit 2.x, за вами уже выехали.
Если вас не зацепила эта диета, то можно пойти дальше, и собрать jQuery только из того, что вам действительно необходимо, что для этого потребуется – читайте в подробном пошаговом руководстве, которому и перевод-то не требуется.
Если вас не впечатляет этот список измений, то это лишь благодаря труду разработчиков jQuery, которые постарались обеспечить полную совместимость API веток 1.х и 2.х, а вот это уже действительно впечатляет.
Ну ладно, не всё так гладко с совместимостью, был этот путь тернист, и проблемы с обновлением будут, вот только искать причину нужно будет в списке изменений версии 1.9, именно эта версия стала поворотной в вопросе совместимости веток.
| 1.0.0 alpha | Первая публикация "для своих", всего 75 скачиваний, вычитка началась |
| 1.0.0 beta | Исправление опечаток и грамматических ошибок. Публикация на Хабре и более 13 000 скачиваний |
| 1.0.0 | Релиз :) Исправлено множество опечаток и несколько ссылок. Добавлена информация о быстродействии селекторов вида "div#id" – спасибо хабрапользователю skorney за тестирование. Более 2 000 скачиваний |
| 1.0.1 | Ещё несколько мелких правок. Спасибо читателям за отзывы. 4500+ |
| 1.0.2 | И ещё… Опубликовал в ePub формате, выложил на scribd, получилось более 8 000 скачиваний и более 10 000 прочтений на scribd |
| 1.0.3 | Обновил книгу вслед за обновлением jQuery, добавил информацию о изменениях в версии 2.х относительно 1.х. Добавил описание виджетов jQWidgets. Удалил описание событий для метода data(). Примеры кода используемые в учебнике теперь доступны на GitHub, так что жду pull-запросов – https://github.com/AntonShevchuk/jquery-for-beginners. Счётчик прочтений на scribd перевалил за 20 тысяч, при этом версию 1.0.2 скачали более 10 тысяч раз… |
| 1.0.4 | Оптимизация шрифтов под печать формата А5. Ушла в тираж. |
| 1.0.5 | Ждёмс… |
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.