Javascript, jComponent 12 января 2020 4 мин. 7387
Toast или всплывающие сообщения - это плагин для сайтов и веб-приложений. Основная цель которого заключается в том, чтобы показать конечному пользователю уведомление заметным образом, которые не мешают его работе и в то же время держат его в курсе.
Подобные плагины я использовал постояно, но когда стал использовать библиотеку jComponent
появилось желание сделать подобный компонент, но с учётом своих потребностей, а также оптимизировать его работу. Поэтому на свет появился этот компонент, который очень легко использовать и настроить под свои задачи.
В данном посте я не буду рассказывать как я его написал, у кого есть желание может взгялнуть на исходник и все разобрать. В этом посте я расскажу как его использовать и опишу основной функционал.
Возможности:
Сперва необходимо подключить библиотеку jComponent
. Как это сделать можно посмотреть этот пост jComponent - #Часть 1, Подключение, DataBinding.
После чего к своим компонентам, добавить компонент toast
. Исходник которого приведен ниже.
COMPONENT('toast', 'timeout:8; position:top-right; loader:true; animate:fade', function(self, config) {
self.singleton();
self.readonly();
self.template = Tangular.compile('<div class="ui-toast {{ type }}" data-id="{{ id }}" {{ if callback }} style="cursor:pointer"{{ fi }}>{{ if loader }}<div class="loader"></div>{{fi}}<i class="fa fa-times"></i><div class="ui-toast-icon">{{if icon }}<i class="fa {{ icon }}"></i>{{fi}}{{if img }}{{ img | raw }}{{fi}}</div><div class="ui-toast-message">{{if date }}<div class="ui-toast-datetime">{{ date }}</div>{{fi}}{{ mess | raw }}</div></div>');
self.items = {};
self.make = function() {
self.aclass('ui-toast-container');
let position = config.position || 'top-right';
self.aclass(position);
self.event('click', 'a,button', function(e) {
e.stopPropagation();
});
self.event('click', '.ui-toast', function() {
var el = $(this);
var id = el.attr('data-id');
var obj = self.items[id];
self.close(obj.id);
});
};
self.configure = function(key, value, init, prev) {
if (init)
return;
if (key=='position') {
self.rclass();
self.aclass('ui-toast-container '+value);
}
}
self.close = function(id) {
var obj = self.items[id];
if (obj.autoClose) clearTimeout(obj.autoClose);
if (!obj) return;
if (obj.callback) obj.callback(obj);
obj.callback = null;
delete self.items[id];
if (config.animate == 'fade') {
self.find('div[data-id="{0}"]'.format(id)).fadeOut('normal', function() { $(this).remove()});
} else if (config.animate == 'slide') {
self.find('div[data-id="{0}"]'.format(id)).slideUp('normal', function() { $(this).remove()});
}
else {
self.find('div[data-id="{0}"]'.format(id)).remove();
}
};
self.success = function(mess, o, callback) {
self.append(mess, o, callback||null, 'success', 'check');
};
self.warning = function(mess, o, callback) {
self.append(mess, o, callback||null, 'warning', 'exclamation-triangle');
};
self.error = function(mess, o, callback) {
self.append(mess, o, callback||null, 'error', 'bell');
};
self.info = function(mess, o, callback) {
self.append(mess, o, callback||null, 'info', 'info-circle');
};
self.append = function(mess, o, callback, tp, ic) {
console.log(config);
if (typeof(o) === 'function') {
callback = o;
o = null;
}
if (!o) o = {};
o.type = o.type || tp || null;
o.icon = o.icon || ic || null;
let id = o.id||Math.floor(Math.random() * 100000);
let type = (o.type) ? o.type : '';
let icon = (o.icon) ? 'fa-' + o.icon : null;
let img = (o.img) ? "<img class='img-rounded img-responsive' src='" + o.img + "'>" : null;
let date = (o.date) ? o.date.format(config.format) : (config.dateAlways) ? new Date().format(config.format): null;
var obj = { id:id, type:type, icon:icon, img:img, mess:mess, date:date, callback: callback };
obj.timeout = o.timeout || config.timeout;
if (obj.timeout) obj.timeout *= 1000;
obj.loader = o.loader || config.loader;
self.items[obj.id] = obj;
var elem = self.template(obj);
self.element.append(elem);
if (config.animate == 'fade') {
self.element.find('.ui-toast:last').hide().fadeIn();
} else if (config.animate == 'slide') {
self.element.find('.ui-toast:last').hide().slideDown();
}
if (obj.loader) {
self.updateLoader(obj);
}
if (obj.timeout) self.autoclose(obj);
};
self.updateLoader = function(obj) {
var el = self.find('.ui-toast[data-id="'+obj.id+'"] .loader');
var transitionTime = (obj.timeout/1000)+'s';
var style = '';
style += '-webkit-transition: width ' + transitionTime + ' ease-in; \
-o-transition: width ' + transitionTime + ' ease-in; \
transition: width ' + transitionTime + ' ease-in; \
background-color: #000; \
opacity:.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40);';
el.attr('style', style);
setTimeout(function() {el.aclass('loaded'); }, 300);
};
self.autoclose = function(obj) {
obj.autoClose = setTimeout(function() {
self.close(obj.id);
}, obj.timeout);
};
})
CSS стили для данного компонента.
/* Toast */
.ui-toast-container { position: fixed; z-index: 10000; padding: 5px 5px 0 0;}
.ui-toast-container.top-center{top:0;right:0;width:100%}
.ui-toast-container.bottom-center{bottom:0;right:0;width:100%}
.ui-toast-container.top-full-width{top:0;right:0;width:100%}
.ui-toast-container.bottom-full-width{bottom:0;right:0;width:100%}
.ui-toast-container.top-left{top:12px;left:12px}
.ui-toast-container.top-right{top:12px;right:12px}
.ui-toast-container.bottom-right{right:12px;bottom:12px}
.ui-toast-container.bottom-left{bottom:12px;left:12px}
.ui-toast-container.bottom-center>div,.ui-toast-container.top-center>div{width:300px;margin-left:auto;margin-right:auto}
.ui-toast-container.bottom-full-width>div,.ui-toast-container.top-full-width>div{width:96%;margin-left:auto;margin-right:auto}
.ui-toast-container>div {width:300px;}
.ui-toast { background-color: white; box-shadow: 0 0 3px #999; border-radius: 3px; font-size: 14px; padding: 15px 15px 15px 10px; margin: 0 0 6px; position: relative; display: flex; opacity:.9;}
.ui-toast .loader{ display: block; width: 0%; position:absolute;left:0;bottom:0;height:4px;/*background-color:#000;opacity:.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)*/}
.ui-toast .loaded { width: 100%; }
.ui-toast:hover { -moz-box-shadow: 0 0 4px #999; -webkit-box-shadow: 0 0 4px #999; box-shadow: 0 0 4px #999; opacity: 1; -ms-filter: alpha(opacity=100); filter: alpha(opacity=100); }
.ui-toast > i { position: absolute; right: 12px; top: 10px; color: #AAB2BD; font-size: 14px; cursor: pointer; text-shadow:0 1px 0 #fff; opacity:.8; }
.ui-toast > i:active { top: 11px; }
.ui-toast > i:hover { color:#000; text-decoration:none; cursor:pointer; opacity:.4; -ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40); filter:alpha(opacity=40) }
.ui-toast-icon{ float: left; font-size: 24px; color: #AAB2BD; line-height: 24px; /*padding-right:0.5em;*/ margin: auto 0.1em; }
.ui-toast-message{ margin: 1px 0 0 10px; color: gray; max-height: 150px; }
.ui-toast-datetime{ font-size: 10px; color: #A0A0A0; margin-bottom: 4px; padding-top: 5px; }
.ui-toast.success{ background-color: #1ab394;}
.ui-toast.error{ background-color: #ed5565;}
.ui-toast.info{ background-color: #2f96b4;}
.ui-toast.warning{ background-color: #F89406;}
.ui-toast.success > i, .ui-toast.error > i, .ui-toast.info > i, .ui-toast.warning > i { color: #fff; }
.ui-toast.success > i:hover, .ui-toast.error > i:hover, .ui-toast.info > i:hover, .ui-toast.warning > i:hover { color:#000; text-decoration:none; opacity:.4; -ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40); filter:alpha(opacity=40) }
.ui-toast.success .ui-toast-icon, .ui-toast.error .ui-toast-icon, .ui-toast.info .ui-toast-icon, .ui-toast.warning .ui-toast-icon { color: #fff; }
.ui-toast.success .ui-toast-message, .ui-toast.error .ui-toast-message, .ui-toast.info .ui-toast-message, .ui-toast.warning .ui-toast-message { color: #fff; }
.ui-toast.success .ui-toast-datetime, .ui-toast.error .ui-toast-datetime, .ui-toast.info .ui-toast-datetime, .ui-toast.warning .ui-toast-datetime { color: #F5F5F5; } { color: #E0E0E0; }
В HTML код необходимо разместить тэг с описанием компонента и его параметрами:
<div data-jc="toast" data-jc-config='timeout:6;format:dd\.MM\.yyyy hh\:mm;animate:fade;'></div>
<!-- или короткое описание компонента -->
<div data---="toast__null__timeout:6;format:dd\.MM\.yyyy hh\:mm;animate:fade;"></div>
В параметрах можно задать следующие свойства по умолчанию:
animate
- стиль анимации при выводе и скрытии сообщения, возможные варианты fade
и slide
timeout
- время жизни сообщения в секундахformat
- формат даты и времени в сообщенииloader
- прогресс бар, true
- выводится, false
- скрыт. По умолчанию true
. position
- позиционирование, место для отображения на экране, возможные значение top-center
, bottom-center
, top-full-width
, bottom-full-width
, top-left
, top-right
, bottom-right
, bottom-left
, bottom-center
, bottom-full-width
. По умолчанию top-right
.Для удобства при работе с плагином, необходимо его инициализировать.
var toast;
FIND('toast', (comp) => toast = comp);
toast.success(message, options, callback)
toast.warning(message, options, callback)
toast.error(message, options, callback)
toast.info(message, options, callback)
Данные методы выводят сообщение определенного типа, уведомления будет с соответствующим цветом и иконкой. Параметры: message
- сообщение (String), options
- дополнительные параметры (Object), callback
- кэллбэк, функция, которая будет вызвана при закрытии уведомления.
toast.reconfigure(options);
- метод позволяет добавить или изменить, параметры компонента, которые были заданы по умолчанию.
//сообщение об успехе
toast.success('<b>Title</b><br>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod');
//сообщение об ошибке, используем форматирование для вывода сообщения
toast.error('<b>{0}</b><br>{1}<br><a href="#" class="btn btn-xs btn-default">Link</a>'.format('Title', 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod'));
//информационное сообщение, к сообщение прикрпим аватар и увеличим время жизни
toast.info('<b>Title</b><br>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod', {'img': 'https://dummyimage.com/80x80/000/fff.jpg', 'timeout': 10});
//уведомление о проблеме, изменим иконку, выведем время и дату проблемы и увеличим время жизни
toast.warning('<b>Title</b><br>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod', {'icon': 'battery', 'date': NOW.add('5 day'), 'timeout': 10});
//изменим местоположение вывода сообщений, будем выводить слева внизу
toast.reconfigure({ position: 'bottom-left' });
//сообщение об ошибке с соответсвущей иконкой, также используем коллбэк, чтобы понять когда было закрыто уведомление
toast.error('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod', {'icon': 'battery-empty'}, function(res){
alert('Close notify - '+res.mess);
});
Также я сделал, демо версию, где используются все возможности данного компонента.
See the Pen Toast - notify popup by Saper639 (@saper639) on CodePen.
Cчитаю, получился добротный компонент, функционал которого можно расширить. Я даже сравнивал объем исходника своего компонента, с подобными для других фреймворков на Vue
, Angular
и я сделал вывод, что у меня получился самый минимальный.
В дальнейшем планирую добавить, звуковое сопровождение, то есть при отображении тревожного сообщения включать сирену, может ещё что-то. Пишите комментируйте, что ещё добавить, удобен ли Вам данный компонент. На Ваши вопросы и комменты я обязательно отвечу.