Простой веб-компонент для создания слайд-шоу
25 января 2023 г.Поскольку я продолжаю экспериментировать и узнавать больше о веб-компонентах, я решил создать простой компонент, чтобы упростить добавление слайд-шоу. Под этим я подразумеваю что-то, что отображает одно изображение, но предоставляет элементы управления для перехода к большему количеству изображений. Я, вероятно, много раз создавал это в прошлом, как в JavaScript, так и в серверном коде, и я подумал, что это будет хорошим кандидатом на роль компонента. Как и в случае с большинством моих демонстраций, с ним можно сделать гораздо больше, но я решил поделиться тем, что у меня есть. Еще раз хочу поблагодарить Саймона Макдональда за помощь в работе над этим кодом. (В конце поста я поделюсь ошибкой, которую я совершил, так как я думаю, что с ней столкнутся другие, а также модифицированная версия, созданная Саймоном.)
Итак, я начал с «проектирования» того, как я хочу использовать компонент на обычной HTML-странице. Я хотел разрешить список изображений, передаваемых через атрибут:
<slide-show images="
https://placekitten.com/500/500,
https://picsum.photos/id/1/500/500,
https://via.placeholder.com/500,
https://placebear.com/500/500,
https://baconmockup.com/500/500
">
</slide-show>
Обратите внимание, что я добавил пробелы вокруг URL-адресов. Я сделал это, чтобы сделать код более читабельным и простым для модификации. (Мне пришлось несколько раз изменить исходные URL-адреса.) Тег также поддерживает атрибут width
и обычно должен использоваться всегда, но по умолчанию он равен 500.
<slide-show width="500" images="
https://placekitten.com/500/500,
https://picsum.photos/id/1/500/500,
https://via.placeholder.com/500,
https://placebear.com/500/500,
https://baconmockup.com/500/500
">
</slide-show>
Теперь давайте посмотрим на код JavaScript. Это не очень долго, поэтому я поделюсь всей частью, а затем расскажу о том, что делает каждая часть:
class SlideShow extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode:'open'});
if(!this.hasAttribute('images')) {
console.warn('slide-show called with no images');
return;
}
if(!this.hasAttribute('width')) {
// default
this.setAttribute('width', 500);
}
/*
Convert attribute into an array and do some trimming so that the end user can have some spacing
*/
this.images = this.getAttribute('images').split(',').map(i => i.trim());
// preload for quicker response, we don't need to wait for this
this.preload(this.images);
this.totalImages = this.images.length;
this.current = 0;
const wrapper = document.createElement('div');
wrapper.innerHTML = `
<img id="currentImage" src="${this.images[this.current]}">
<p>
<button id="prevButton">Previous</button>
Picture <span id="currentPicture">1</span> of ${this.totalImages}
<button id="nextButton">Next</button>
</p>
`;
this.$nextButton = wrapper.querySelector('#nextButton');
this.$prevButton = wrapper.querySelector('#prevButton');
this.$currentPicture = wrapper.querySelector('#currentPicture');
this.$image = wrapper.querySelector('#currentImage');
const style = document.createElement('style');
style.innerHTML = `
div {
width: ${this.getAttribute('width')}px
}
p {
text-align: center;
}
`;
shadow.appendChild(wrapper);
shadow.appendChild(style);
}
connectedCallback() {
this.$nextButton.addEventListener('click', this.nextImage.bind(this));
this.$prevButton.addEventListener('click', this.prevImage.bind(this));
}
nextImage() {
if(this.current+1 == this.totalImages) return;
this.current++;
this.updateImage();
}
prevImage() {
if(this.current == 0) return;
this.current--;
this.updateImage();
}
updateImage() {
this.$image.src = this.images[this.current];
this.$currentPicture.innerText = this.current+1;
}
preload(i) {
for(let x=0; x<i.length; x++) {
let img = new Image();
img.src = i[x];
}
}
}
customElements.define('slide-show', SlideShow);
Итак, сверху я начну с некоторой базовой проверки. Если вы не передаете изображения, тегу нечего делать, поэтому он может прерваться. Я упомянул, что тег поддерживает атрибут ширины, и хотя он установлен по умолчанию, я, вероятно, буду постоянно использовать его в рабочей среде. Эта часть,
this.images = this.getAttribute('images').split(',').map(i => i.trim());
Это бит, который позволяет мне добавлять разрывы строк и прочее вокруг URL-адресов. Мне это очень нравится, так как разработчику намного проще использовать тег.
Пользовательский опыт FTW!
Говоря об опыте, я добавил функцию preload
, которая автоматически загружает все изображения. Теоретически это сделает слайд-шоу более быстрым, когда пользователь перемещается по изображениям. Я не жду, пока он завершится, что, по моему мнению, является хорошим компромиссом между попыткой загрузить что-то раньше и предоставлением пользователю возможности навигации, как только он захочет.
Далее у меня есть базовая компоновка компонента. Это просто изображение с абзацем под ним. Этот абзац содержит мои кнопки, а также некоторый текст, сообщающий пользователю, на каком изображении он находится, а также сколько всего изображений доступно. Я также создаю элемент стиля с небольшим контролем макета. Это может быть красивее. Я не умею красиво.
Это большая часть конструктора. В обработчике событий connectedBacllback
я добавляю свои прослушиватели событий к кнопкам, стараясь правильно привязать область this
, и я полностью не испортил это в первый раз. , честный. (Я сделал совершенно другую ошибку.) Обработчики событий выполняют базовые проверки «конца диапазона» и просто обновляют значение для текущего изображения, а затем связываются с updateImage
для обновления DOM.
Вы можете увидеть все это в действии ниже:
https://codepen.io/cfjedimaster/pen/eYjygxN?embedable=true р>
Исходный код этой демонстрации находится в моем репозитории GitHub здесь
Итак, позвольте мне оставить вас с несколькими примечаниями.
* В моей первоначальной версии я использовал getAttribute
и setAttribute
с именем атрибута, написанным в верблюжьем регистре. Вы не можете этого сделать. У меня был currentImage
, который не является допустимым атрибутом веб-компонента. Я помню это сейчас, но не знал, когда строил.
* Я упомянул, что Саймон помог мне, и он также создал свою собственную версию. (Его версия была собрана до того, как я добавил текст.) Вы можете найти ее здесь.
* В этом компоненте чего-то не хватает, что мне нужно добавить, и я сделаю это в следующем посте. Должна быть возможность изменять изображения с помощью JavaScript. Теоретически вы можете изменить их сейчас, но это ничего не изменит. Веб-компоненты определенно позволяют вам поддерживать это, и я собираюсь создать вторую версию, чтобы продемонстрировать это! (И дайте мне повод снова вести блог!)
Также опубликовано здесь
Оригинал