Кнопки со встроенным индикатором выполнения
Просмотр
Скачать
Индикаторы выполнения (англ. Progress bars) стали очень популярны в последнее время, и есть большое количество плагинов, которые помогут вам добавить индикатор выполнения на ваш сайт. Но как сделать такой индикатор самим? Проблема в том, что уже есть множество реализаций, поэтому в этом уроке мы собираемся запрограммировать кое-что другое – кнопки, в которые будут встроены индикаторы выполнения.
Они отлично подходят для отображения прогресса, пока отправляются формы или загружается контент с помощью AJAX. Кроме того, эти кнопки будут использовать стили и трансформации CSS, что сделает их легко настраиваемыми под нужды пользователя.
HTML
В первой части урока мы напишем разметку HTML. Она представляет собой стандартный HTML документ, включающий в себя два дополнительных источника, которые мы обсудим позже – таблицу стилей styles.css и файл JavaScript script.js. Дополнительно я подключил библиотеку jQuery и шрифт Raleway из Google web fonts.
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Tutorial: Buttons with built-in progress meters</title>
<link href="http://fonts.googleapis.com/css?family=Raleway:400,700" rel="stylesheet" />
<!-- The Stylesheets -->
<link href="assets/css/style.css" rel="stylesheet" />
</head>
<body>
<h1>Progress Buttons</h1>
<a id="submitButton" href="#" class="progress-button">Submit</a>
<a id="actionButton" href="#" class="progress-button green" data-loading="Working.." data-finished="Finished!" data-type="background-bar">Action!</a>
<a id="generateButton" href="#" class="progress-button red" data-loading="Generating.." data-finished="Download" data-type="background-vertical">Generate</a>
<h1>Progress Control</h1>
<a id="controlButton" href="#" class="progress-button">Start</a>
<div class="control-area">
<a class="command increment">Increment</a>
<a class="command set-to-1">Set to 1%</a>
<a class="command set-to-50">Set to 50%</a>
<a class="command finish">Finish</a>
</div>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="assets/js/script.js"></script>
</body>
</html>
Эта разметка очень простая. Кнопки с индикатором выполнения определены как обычные гиперссылки. Чтобы плагин смог распознать их и превратить в кнопки со встроенным индикатором процесса, к ним должен быть применен класс .progress-button.
Кнопки могут быть также сконфигурированы установкой трех data- атрибутов:
- data-type определяет какой тип индикатора выполнения будет показан. В настоящее время поддерживаются три типа: background-horizontal (горизонтальный, установлен по умолчанию), background-bar (в виде полосы) и background-vertical (вертикальный);
- data-loading определяет какой текст будет показан, пока индикатор выполнения продвигается. Значение по умолчанию – «Loading..»;
- data-finished отвечает за текст, который появится на кнопке, когда процесс завершится. Значение по умолчанию – «Done!».
- Если вы не определите какой-нибудь атрибут, то для него будет использовано значение по умолчанию.

Кнопки со встроенным индикатором выполнения
Код jQuery
В этой части урока мы напишем JavaScript и jQuery код для того, чтобы наши кнопки заработали. Код организован в виде шести плагинов jQuery, начинающихся одинаково: progressInitialize, progressStart, progressIncrement, progressTimed, progressSet и progressFinish. Я достаточно подробно прокомментировал код, так что вы легко сможете разобраться в нем:
assets/js/script.js
$(document).ready(function(){
// Конвертируем все ссылки с классом progress-button
// в настоящие кнопки с индикатором выполнения.
// Вам нужно вызвать эту функцию, как только загрузится страница
//Если вы добавите кнопки позже, вам нужно будет вызвать эту функцию только для них.
$('.progress-button').progressInitialize();
//Ожидаем клика по одной из первых трех кнопок и начинаем анимацию прогресса.
$('#submitButton').click(function(e){
e.preventDefault();
// Эта функция показывает индикатор выполнения
// в течение определенного промежутка времени.
$(this).progressTimed(2);
});
$('#actionButton').click(function(e){
e.preventDefault();
$(this).progressTimed(2);
});
$('#generateButton').one('click', function(e){
e.preventDefault();
// Можно использовать функцию обратного вызова (callback).
var button = $(this);
button.progressTimed(3, function(){
//В этой функции обратного вызова вы можете установить для атрибута кнопки href
// значение URL сгенерированного файла. Здесь мы только
// устанавливаем новый обработчик события, который генерирует предупреждение.
button.click(function(){
alert('Showing how a callback works!');
});
});
});
// Пользовательская обработка прогресса.
var controlButton = $('#controlButton');
controlButton.click(function(e){
e.preventDefault();
// При необходимости можно вызвать функцию progressStart
// Она будет симулировать действие каждые 2 секунды,
// если индикатор выполнения не был увеличен.
controlButton.progressStart();
});
$('.command.increment').click(function(){
// Инкрементируем индикатор на 10%. Можно передать число как аргумент функции
// чтобы увеличивать на другое значение.
controlButton.progressIncrement();
});
$('.command.set-to-1').click(function(){
// Устанавливаем индикатор прогресса на определенный процент.
controlButton.progressSet(1);
});
$('.command.set-to-50').click(function(){
controlButton.progressSet(50);
});
$('.command.finish').click(function(){
// Устанавливаем индикатор прогресса в 100 % и выводим текст о готовности.
controlButton.progressFinish();
});
});
// Функционал индикатора выполнения доступен в виде ряда плагинов.
// Вы можете поместить этот код в отдельный файл, если хотите соблюдать порядок.
(function($){
// Создание ряда jQuery плагинов, которые вы можете использовать, чтобы инициализировать
// и контролировать индикаторы выполнения.
$.fn.progressInitialize = function(){
// Эта функция создает необходимую разметку для индикатора выполнения
//и определяет несколько «слушателей» событий.
// Цикл по всем кнопкам:
return this.each(function(){
var button = $(this),
progress = 0;
// Извлечение атрибутов данных в объект option.
// Если атрибуты не указаны, к ним будут применены значения по умолчанию.
var options = $.extend({
type:'background-horizontal',
loading: 'Loading..',
finished: 'Done!'
}, button.data());
// Добавляем атрибуты data-, если они отсутствуют у элемента.
// Они применяются в нашем CSS коде, чтобы выводить сообщения.
button.attr({'data-loading': options.loading, 'data-finished': options.finished});
// Добавляем необходимую разметку к кнопке для индикатора выполнения.
var bar = $('<span class="tz-bar ' + options.type + '">').appendTo(button);
// Событие progress заставляет кнопку обновить индикатор выполнения.
button.on('progress', function(e, val, absolute, finish){
if(!button.hasClass('in-progress')){
// Это первое событие выполнения для кнопки
// (или первое после завершения предыдущего прогона). Повторно инициализируем
// выполнение и удаляем некоторые классы, которые могли остаться.
bar.show();
progress = 0;
button.removeClass('finished').addClass('in-progress')
}
// val, absolute и finish – это сведения о событии, отправляемые функциями
// progressIncrement и progressSet, которые вы можете увидеть ближе к концу этого файла.
if(absolute){
progress = val;
}
else{
progress += val;
}
if(progress >= 100){
progress = 100;
}
if(finish){
button.removeClass('in-progress').addClass('finished');
bar.delay(500).fadeOut(function(){
//Запускаем пользовательское событие progress-finish.
button.trigger('progress-finish');
setProgress(0);
});
}
setProgress(progress);
});
function setProgress(percentage){
bar.filter('.background-horizontal,.background-bar').width(percentage+'%');
bar.filter('.background-vertical').height(percentage+'%');
}
});
};
// progressStart симулирует активность на индикаторе выполнения. Вызываем ее вначале,
// если выполнение займет долгое время.
$.fn.progressStart = function(){
var button = this.first(),
last_progress = new Date().getTime();
if(button.hasClass('in-progress')){
//Не запускаем во второй раз!
return this;
}
button.on('progress', function(){
last_progress = new Date().getTime();
});
// Каждые полсекунды проверяем, был ли прогресс увеличен за последние 2 секунды.
var interval = window.setInterval(function(){
if( new Date().getTime() > 2000+last_progress){
// Здесь не было активности за последние 2 секунды.
// Увеличиваем индикатор выполнения немного, чтобы показать, что что-то происходит.
button.progressIncrement(5);
}
}, 500);
button.on('progress-finish',function(){
window.clearInterval(interval);
});
return button.progressIncrement(10);
};
$.fn.progressFinish = function(){
return this.first().progressSet(100);
};
$.fn.progressIncrement = function(val){
val = val || 10;
var button = this.first();
button.trigger('progress',[val])
return this;
};
$.fn.progressSet = function(val){
val = val || 10;
var finish = false;
if(val >= 100){
finish = true;
}
return this.first().trigger('progress',[val, true, finish]);
};
// Эта функция создает индикатор выполнения, который
// завершается через определенный промежуток времени.
$.fn.progressTimed = function(seconds, cb){
var button = this.first(),
bar = button.find('.tz-bar');
if(button.is('.in-progress')){
return this;
}
// Определяем переход transition в течение всей работы индикатора.
// CSS сделает работу по анимации индикатора выполнения за нас.
bar.css('transition', seconds+'s linear');
button.progressSet(99);
window.setTimeout(function(){
bar.css('transition','');
button.progressFinish();
if($.isFunction(cb)){
cb();
}
}, seconds*1000);
};
})(jQuery);
РrogressInitialize устанавливает «слушателя» для пользовательского события прогресса, которое вызывается другими функциями, когда необходимо обновить индикатор. Благодаря пользовательскому событию у нас есть возможность использовать полностью независимые функции, такие как progressStart, которая управляет своим временем и состоянием – при этом функция progresInitialize может и не знать о progressStart.
Другая важная деталь заключается в установке двух специальных классов для кнопок: .in-progress во время передвижения индикатора выполнения, и .finished, когда выполнение завершено. Они используются для обновления текста кнопок, как вы увидите в следующей секции.
CSS
Выше я упоминал, что мы определяем два CSS класса на кнопках - .in-progress и .finished. Но как добавление одного из этих классов изменяет текст кнопки? Да очень просто – мы используем хитрый ход в CSS, включающий в себя использование CSS3 оператора attr, который в комбинации с контентом может устанавливать текст :before или :after псевдоэлемента к атрибуту элемента. Вам все станет ясно, если вы посмотрите код сами (строки 44-52):
assets/css/styles.css
.progress-button{
display: inline-block;
font-size:24px;
color:#fff !important;
text-decoration: none !important;
padding:14px 60px;
line-height:1;
overflow: hidden;
position:relative;
box-shadow:0 1px 1px #ccc;
border-radius:2px;
background-color: #51b7e6;
background-image:-webkit-linear-gradient(top, #51b7e6, #4dafdd);
background-image:-moz-linear-gradient(top, #51b7e6, #4dafdd);
background-image:linear-gradient(top, #51b7e6, #4dafdd);
}
/* Скрываем первоначальный текст кнопки. После этого текст loading или finished
будет показан в элементе :after поверх кнопки. */
.progress-button.in-progress,
.progress-button.finished{
color:transparent !important;
}
.progress-button.in-progress:after,
.progress-button.finished:after{
position: absolute;
z-index: 2;
width: 100%;
height: 100%;
text-align: center;
top: 0;
padding-top: inherit;
color: #fff !important;
left: 0;
}
/* Если класс .in-progress class применен к кнопке, отображаем содержимое атрибута data-loading на кнопку */
.progress-button.in-progress:after{
content:attr(data-loading);
}
/* То же самое для класса .finished */
.progress-button.finished:after{
content:attr(data-finished);
}
/* Яркая полоска, растущая в зависимости от прогресса */
.progress-button .tz-bar{
background-color:#e667c0;
height:3px;
bottom:0;
left:0;
width:0;
position:absolute;
z-index:1;
border-radius:0 0 2px 2px;
-webkit-transition: width 0.5s, height 0.5s;
-moz-transition: width 0.5s, height 0.5s;
transition: width 0.5s, height 0.5s;
}
/* Полоска может быть, как горизонтальная, так и вертикальная */
.progress-button .tz-bar.background-horizontal{
height:100%;
border-radius:2px;
}
.progress-button .tz-bar.background-vertical{
height:0;
top:0;
width:100%;
border-radius:2px;
}
Остальной код настраивает кнопки и встроенный индикатор выполнения. В файле styles.css я также подключил две дополнительные цветовые темы и некоторые другие правила, которые не приведены здесь, но вы можете посмотреть их сами в исходном коде.
Готово!
Код, который мы написали сегодня, готов для настройки. Просто откройте файл styles.css в вашем любимом редакторе кода и поменяйте цвета, шрифты или стили так, чтобы они подходили к вашему сайту. Измените текст, отредактировав HTML и атрибуты данных. Или вы даже можете улучшить код с помощью каких-нибудь крутых новинок. В таком случае не забудьте поделиться им в комментариях.