Карусель — широко используемый компонент в веб-приложениях. Он представляет собой список элементов (данных). Одновременно представлен только один элемент (называемый «текущий»), пользователь может просматривать предыдущий или следующий элемент в пользовательском интерфейсе.
В этом посте я реализую простую карусель с collarjs. На следующей диаграмме показано, как работает окончательный вариант. Мы пройдем весь процесс, чтобы построить его.
Примечание: код можно найти в репозитории github
Или вы можете проверить пример карусели здесь
Давайте сначала подумаем, как мы будем использовать карусель:
// create the carousel with an element id
var myCarousel = carousel();
myCarousel.init('my-carousel');
// set the items of the carousel
myCarousel.setItems([
{ img: 'https://unsplash.it/600/?random&abc=1',
title: 'Example Item Title 1',
subtitle: 'subtitle for item 1' },
{ img: 'https://unsplash.it/600/?random&abc=2',
title: 'Example Item Title 2',
subtitle: 'subtitle for item 2' },
{ img: 'https://unsplash.it/600/?random&abc=3',
title: 'Example Item Title 3',
subtitle: 'subtitle for item 3'}
]);
// switch to the next item
myCarousel.showNext();
// switch to the previous item
myCarousel.showPrev();
Поскольку Collarjs управляется сообщениями, эти API могут быть представлены в виде сообщений:
// 'init carousel' message { msg: "init carousel", id: "element id" }
// 'set items' message { msg: "set items", items: [] // list of item objects }
// switch to previous item { msg: "prev item" }
// switch to next item { msg: "next item" }
Затем давайте создадим конвейер для обработки каждого из этих сообщений. Прежде чем мы начнем обрабатывать сообщения, нам нужно создать входной узел для приема сообщений и выходной узел для возврата результатов.
// create a namespace
var ns = window.collar.ns('com.collartechs.example.carousel');
var input = ns.input('carousel input');
var output = ns.output('carousel output');
Обработка сообщения «init carousel»
Во время запуска карусели мы просто создаем контейнер для размещения элементов карусели и инициируем датчик для наблюдения за пользовательским вводом в пользовательском интерфейсе. Фильтр (оператор when) используется, чтобы убедиться, что здесь обрабатывается только сообщение «init carousel». Идентификатор элемента, полученный из сообщения «init carousel», сохраняется в переменной id. Контейнер карусели определяется в строке шаблона. См. следующий код:
var id; // element id for container var carouselTemplate = ` <div class="carousel"> <ol class="carousel-content"></ol> <div class="carousel-prev">prev</div> <div class="carousel-next">next</div> </div> `;
var uiSensor = ns.sensor('carousel UI sensor', function (options) { var sensor = this; if (options === 'init carousel') { // watch clicking prev event, and send 'prev item' message document.querySelector('#' + id + ' .carousel-prev') .addEventListener('click', function () { sensor.send({ msg: 'prev item' }); }); // watch clicking next event, and send 'next item' message document.querySelector('#' + id + ' .carousel-prev') .addEventListener('click', function () { sensor.send({ msg: 'next item' }); }); } });
input .when('init carousel', function (signal) { return signal.get('msg') === 'init carousel'; }) .do('init carousel container', function (signal) { id = signal.get('id'); var container = document.querySelector('#' + id); container.innerHTML = carouselTemplate; }) .do('init UI sensor', function (signal) { uiSensor.watch('init carousel'); }) .to(output); // just output the same message
В приведенном выше коде мы напрямую передаем сообщение на вывод, если вы хотите сообщить внешнему миру, что карусель инициирована, вы можете использовать оператор map для создания сообщения «карусель инициирована» и поместить дополнительный данные в сообщении, например, id карусели:
.map('generate "carousel initatiated" message', function (signal) {
return signal.new({
msg: 'carousel initiated',
id: signal.get('id')
});
})
.to(output);
Обработка сообщения «установить элементы»
После того, как компонент карусели создан, нам нужно настроить его, передав ему список элементов. Это обрабатывается сообщением «установить элементы»:
input
.when('set items')
.do('store items in memory')
.do('create items elements')
.do('change current index to 0')
.do('show current item')
.to(output);
Для представления карусели мы используем следующую структуру данных:
var data = {
items: [], // the list of items
current: 0 // the index of current item
}
Реализация проста:
const carouselItemTemplate = '<li class="carousel-item {CURRENT}">' + '<img src="{IMG}"/>' + '<div class="carousel-desc">' + '<div class="carousel-title">' + '<h1>{TITLE}</h1>' + '</div>' + '<div class="carousel-calories">' + 'Subtitle: <span>{SUBTITLE}</span>' + '</div>' + '</div>' + '</li>';
input .when('set items', function (signal) { return signal.get('msg') === 'set items'; }) .do('store items in memory', function (signal) { data.items = signal.get('items'); }) .do('create items elements', function (signal) { var carouselElemItemStr = ''; for (var i = 0; i < data.items.length; i++) { carouselElemItemStr += carouselItemTemplate .replace('{CURRENT}', '') .replace('{IMG}', data.items[i].img) .replace('{TITLE}', data.items[i].title) .replace('{SUBTITLE}', data.items[i].subtitle); } var carouselContentEle = document.querySelector('#' + id + ' .carousel-content'); carouselContentEle.innerHTML = carouselElemItemStr; }) .do('change current index to 0', function (signal) { data.current = 0; }) .do('show current item', function (signal) { var oldCurrentItem = document.querySelector('.current'); if (oldCurrentItem) oldCurrentItem.classList.remove('current');
var newCurrentItem = document.querySelector('#' + id + ' li.carousel-item:nth-of-type(' + (data.current+1) + ')'); if (newCurrentItem) oldCurrentItem.classList.add('current'); }) .map('generate "items changed" message', function (signal) { return signal.new({ msg: 'items changed', items: signal.get('items') }); }) .to(output);
Через выходной узел отправляется сообщение об изменении элементов со списком элементов в поле items.
Обработка сообщений «предыдущий элемент» и «следующий элемент»
Когда получено сообщение «предыдущий элемент» или «следующий элемент», мы меняем текущий индекс в переменной данных и отображаем новый текущий элемент, добавляя к нему «текущий» класс.
input
.when('next item')
.do('change current index to next')
.do('show current item')
.map('generate "current item changed" message')
.to(output);
Вот реализация:
input .when('next item', function (signal) { return signal.get('msg') === 'next item'; }) .do('change current index to next', function (signal) { data.current = (data.current + 1) % data.items.length; }) .do('show current item', function (signal) { var oldCurrentItem = document.querySelector('.current'); if (oldCurrentItem) oldCurrentItem.classList.remove('current');
var newCurrentItem = document.querySelector('#' + id + ' li.carousel-item:nth-of-type(' + (data.current+1) + ')'); if (newCurrentItem) oldCurrentItem.classList.add('current'); }) .map('genereate "current item changed" message', function (signal) { return signal.new({ msg: 'current item changed', current: data.current }); }) .to(output);
Обработка «предыдущего элемента» аналогична «следующему элементу», разница здесь в том, что мы меняем текущий индекс на предыдущий.
input .when('previous item', function (signal) { return signal.get('msg') === 'next item'; }) .do('change current index to next', function (signal) { data.current = data.current === 0 ? data.items.length - 1 : data.current - 1; }) .do('show current item', function (signal) { var oldCurrentItem = document.querySelector('.current'); if (oldCurrentItem) oldCurrentItem.classList.remove('current');
var newCurrentItem = document.querySelector('#' + id + ' li.carousel-item:nth-of-type(' + (data.current+1) + ')'); if (newCurrentItem) oldCurrentItem.classList.add('current'); }) .map('genereate "current item changed" message', function (signal) { return signal.new({ msg: 'current item changed', current: data.current }); }) .to(output);
Перенести сообщение в NodeAPI
Теперь у нас есть 4 сообщения для карусели:
- инициализировать карусель
- набор предметов
- следующий элемент
- предыдущий элемент
Мы можем обернуть эти 4 сообщения в API асинхронного обратного вызова, похожее на узел (используя API воротника toNode):
collar.toNode(input, output) : Function
API toNode принимает входной узел и выходной узел, возвращает узел, подобный асинхронной функции.
function nodeFunc(message, callback, [non-interruptible]);
Обратный вызов принимает два аргумента: ошибку и выходной сигнал. В отличие от стандартной асинхронной функции, похожей на узел, третий аргумент сообщает Collarjs, может ли сообщение быть прервано. По умолчанию Collarjs освобождает ресурс потока, когда сообщение обрабатывается узлом, и дает возможность другим сообщениям быть обработанными. Иногда вы хотите, чтобы сообщение завершило обработку до того, как будут обработаны любые другие сообщения, это можно сделать, установив false в качестве третьего аргумента.
Давайте создадим 4 API, обернув 4 сообщения:
var apiFunc = window.collar.toNode(input, output);
function carousel() { return { init : function (id, done) { apiFunc({ msg: 'init carousel', id: id }, done, false); // use the false argument to make the message non-interruptible }, setItems : function (items, done) { apiFunc({ msg: 'set items', items: items }, done, false); }, next : function (done) { apiFunc({ msg: 'next item' }, done, false); }, prev : function (done) { apiFunc({ msg: 'previous item' }, done, false); } } }
Теперь мы можем использовать эти API для настройки карусели:
var myCarousel = carousel();
myCarousel.init('carouselId');
myCarousel.setItems([
{
img: 'https://unsplash.it/600/?random&abc=1',
title: 'Example Title 1',
subtitle: 'subtitle',
},
{
img: 'https://unsplash.it/600/?random&abc=2',
title: 'Example Title 2',
subtitle: 'subtitle',
},
{
img: 'https://unsplash.it/600/?random&abc=3',
title: 'Example Title 3',
subtitle: 'subtitle',
}
]);
myCarousel.next();
Поймите, как работает карусель
Сначала установите Collar-dev-сервер и запустите его.
sudo npm install collar-dev-server -g
collar-dev-server
// check dev tool from http://localhost:7500
Запустите пример
Клонировать с github
git clone https://github.com/bhou/collar-example-carousel.git
sudo npm install http-server -g
http-server .
Откройте карусель в браузере
http://localhost:8080/index.html
Или напрямую запустить онлайн-пример
http://collarjs.com/examples/carousel/index.html
Теперь проверьте страницу сервера разработки воротника по адресу http://localhost:7500
, чтобы увидеть, как работает карусель. Вы можете записать сигналы времени выполнения, нажав кнопку записи в инструменте разработки воротника.
Ресурсы
Код можно найти в репозитории github (collar-example-carousel)
Поиграйте с примером на сайте Collar.js