I den här handledningen skall vi skapa ett bildgalleri (lightbox) med ren JavaScript. Ett modalt bildgalleri används för att visa bilder i fullskärm i en överliggande ruta på den aktuella sidan.
Denna plugin är beroende av annytab.effects (Rena JavaScript-effekter) som vi har skrivit om i ett tidigare blogginlägg och Font Awesome för ikoner.
Vi ska skapa ett bildgalleri som kan användas för att visa en eller flera bilder i ett modalfönster. Bilder i samma grupp kan ha ett bildspel och bildgalleriet har sidhantering om det finns mer än en bild i en grupp. Bilder kan också ha en bildtext som visas längst ner i rutan. Modalrutan kan stängas genom att klicka utanför rutan (tillval) eller genom att klicka på x:et i övre högra hörnet.
Det här tillägget har testats och fungerar med Google Chrome (75.0.3770.100), Mozilla Firefox (67.0.4), Microsoft Edge (42.17134.1.0) och Internet Explorer (11.829.17134.0), detta utan någon polyfill. Om du vill stödja äldre webbläsare kan du läsa vårt inlägg om transpilering och komplettering av JavaScript.
Utseende (CSS)
Rutan är centrerad på skärmen och stängnings-knappen är skapad i ren CSS. Vi använder Font Awesome för ikoner.
/* Annytab lightbox*/
.annytab-lightbox-container {
display: none;
z-index: 100;
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
text-align: center;
background-color: #000000;
background-color: rgba(0, 0, 0, 0.7);
}
.annytab-lightbox-margin {
display: block;
margin: 40px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.annytab-lightbox-wrapper {
display: inline-block;
position: relative;
max-width: 100%;
background-color: #ffffff;
border-radius: 8px;
top: calc(50vh - 50px); /* adjust for margin */
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
.annytab-lightbox-padding {
display: block;
padding: 10px;
}
.annytab-lightbox-image {
display: inline-block;
max-width: 100%;
max-height: calc(100vh - 100px); /* margin + padding */
padding: 0;
margin: 0;
}
.annytab-lightbox-left-arrow {
display: block;
z-index: inherit;
position: absolute;
left: 20px;
top: 50%;
margin-top: -16px;
cursor: pointer;
width: 32px;
height: 32px;
border-radius: 4px;
background-color: #000000;
opacity: 0.5;
filter: alpha(opacity=50);
font-size: 30px;
line-height: 32px;
color: #ffffff;
}
.annytab-lightbox-right-arrow {
display: block;
z-index: inherit;
position: absolute;
right: 20px;
top: 50%;
margin-top: -16px;
cursor: pointer;
width: 32px;
height: 32px;
border-radius: 4px;
background-color: #000000;
opacity: 0.5;
filter: alpha(opacity=50);
font-size: 30px;
line-height: 32px;
color: #ffffff;
}
.annytab-lightbox-caption {
display: none;
position: absolute;
bottom: 15px;
left: 10px;
right: 10px;
max-height: 36px;
overflow-y: auto;
background-color: #000000;
opacity: 0.6;
filter: alpha(opacity=60);
padding: 10px;
color: #ffffff;
text-align: left;
}
.annytab-lightbox-close {
position: absolute;
width: 24px;
height: 24px;
top: 8px;
right: 8px;
cursor: pointer;
opacity: 0.6;
filter: alpha(opacity=60);
}
.annytab-lightbox-close:hover {
opacity: 1;
filter: alpha(opacity=100);
}
.annytab-lightbox-close:before, .annytab-lightbox-close:after {
position: absolute;
right: 12px;
content: ' ';
height: 24px;
width: 2px;
background-color: #ffffff;
}
.annytab-lightbox-close:before {
transform: rotate(45deg);
}
.annytab-lightbox-close:after {
transform: rotate(-45deg);
}
JavaScript
Denna plugin har en konstruktor som tar alternativ som en parameter. Vi lägger till klickhändelser för alla länkar med en given väljare (selector) och det här tillägget har två offentliga metoder, open och close, som kan anropas från dina skript.
var annytab = annytab || {};
annytab.lightbox = (function () {
'use_strict';
// Constructor
function lightbox(opts)
{
// Set default values for parameters
opts = opts || {};
// Set options
this.options = { selector: '.annytab-lightbox-popup', fade_duration: 1000, close_click_outside: true, slideshow: true, slideshow_interval: 10000 };
for (var option in this.options) {
if (opts.hasOwnProperty(option) === true) {
this.options[option] = opts[option];
}
}
// Set variables
resetVariables(this);
// Get all links that should have a lightbox
var links = document.querySelectorAll(this.options.selector);
// Add events
addLinkEvents(this, links);
} // End of the constructor
// Reset variables to default values
function resetVariables(lb)
{
lb.current_slide = null;
lb.last_slide = null;
lb.container = null;
lb.wrapper = null;
lb.close_button = null;
lb.automatic_slideshow = null;
lb.left_arrow = null;
lb.right_arrow = null;
lb.caption_container = null;
} // End of the resetVariables method
// Add events
function addLinkEvents(lb, links)
{
// Loop links
for (var i = 0; i < links.length; i++)
{
// Add a click event
window.onload = links[i].addEventListener('click', function (event) {
// Prevent default click behaviour
event.preventDefault();
// Open the lightbox
lb.open(this);
}, false);
}
} // End of the addLinkEvents method
// Add container events
function addContainerEvents(lb)
{
// Add a close event
window.onload = lb.close_button.addEventListener('click', function (event) {
// Prevent default click behaviour
event.preventDefault();
// Close the lightbox
lb.close();
}, false);
// Add a close event
if (lb.options.close_click_outside === true)
{
window.onload = lb.container.addEventListener('click', function (event) {
// Prevent default click behaviour
event.preventDefault();
// Close the lightbox
if (event.target.contains(lb.wrapper) === true)
{
lb.close();
}
}, false);
}
// Add paging if there is more than 1 slide
if (lb.last_slide > 0)
{
// Show arrows
lb.left_arrow.style.display = 'block';
lb.right_arrow.style.display = 'block';
// Add left arrow click event
window.onload = lb.left_arrow.addEventListener('click', function (event) {
// Prevent default click behaviour
event.preventDefault();
// Show the previous slide
lb.showSlide(-1);
// Turn of the slideshow
clearInterval(lb.automatic_slideshow);
}, false);
// Add right arrow click event
window.onload = lb.right_arrow.addEventListener('click', function (event) {
// Prevent default click behaviour
event.preventDefault();
// Show the next slide
lb.showSlide(1);
// Turn of the slideshow
clearInterval(lb.automatic_slideshow);
}, false);
// Create a slideshow
if (lb.options.slideshow === true)
{
lb.automatic_slideshow = setInterval(function () { lb.showSlide(1); }, lb.options.slideshow_interval);
}
}
else
{
// Hide arrows
lb.left_arrow.style.display = 'none';
lb.right_arrow.style.display = 'none';
}
} // End of the addContainerEvents method
// Show a slide
lightbox.prototype.showSlide = function (step)
{
// Set the current slide
this.current_slide += step;
// Make sure that the slide id not is outside borders
if (this.current_slide > this.last_slide) {
this.current_slide = parseInt(0);
}
if (this.current_slide < 0) {
this.current_slide = parseInt(this.last_slide);
}
// Get slides
var slides = this.container.querySelectorAll('.annytab-lightbox-image');
var next_slide = this.container.querySelector('img[data-lightbox-id="' + this.current_slide + '"]');
// Set a caption
var caption = next_slide.getAttribute('data-lightbox-caption');
if (caption !== null)
{
this.caption_container.innerHTML = caption;
this.caption_container.style.display = 'block';
}
else
{
this.caption_container.style.display = 'none';
}
// Hide slides
for (var i = 0; i < slides.length; i++)
{
slides[i].style.display = 'none';
}
// Fade in the next slide
annytab.effects.fadeIn(next_slide, this.options.fade_duration, 'inline-block');
}; // End of the showSlide method
// Open a lightbox
lightbox.prototype.open = function (link)
{
// Get the href attribute
var href = link.getAttribute('href');
// Get the group
var group = link.getAttribute('data-lightbox-group');
// Get the caption
var caption = link.getAttribute('data-lightbox-caption');
// Add the first image
var source = '<img data-lightbox-id="0" src="' + href + '" class="annytab-lightbox-image" alt="image" style="display:none;"';
source += caption !== null ? ' data-lightbox-caption="' + caption : '';
source += '" />';
// Create a counter
var counter = 1;
// Find all images in the group
var images = document.querySelectorAll('[data-lightbox-group="' + group + '"]');
// Loop images
for (var i = 0; i < images.length; i++)
{
var url = images[i].getAttribute('href');
if (url !== href)
{
source += '<img data-lightbox-id="' + counter + '" src="' + url + '" class="annytab-lightbox-image" alt="image" style="display:none;"';
source += images[i].getAttribute('data-lightbox-caption') !== null ? ' data-lightbox-caption="' + images[i].getAttribute('data-lightbox-caption') : '';
source += '" />';
counter += 1;
}
}
// Get the last slide and set the current slide
this.last_slide = counter - 1;
this.current_slide = parseInt(-1);
// Create a lightbox
this.container = document.createElement('div');
this.container.setAttribute('class', 'annytab-lightbox-container');
this.container.insertAdjacentHTML('beforeend', '<div class="annytab-lightbox-margin">'
+ '<div class="annytab-lightbox-wrapper">'
+ '<div class="annytab-lightbox-padding">'
+ source
+ '<div class="annytab-lightbox-left-arrow"><i class="fas fa-angle-left"></i></div>'
+ '<div class="annytab-lightbox-right-arrow"><i class="fas fa-angle-right"></i></div>'
+ '<div class="annytab-lightbox-caption"></div>'
+ '</div></div></div>'
+ '<div class="annytab-lightbox-close"></div >');
document.body.appendChild(this.container);
// Get references
this.wrapper = this.container.querySelector('.annytab-lightbox-wrapper');
this.close_button = this.container.querySelector('.annytab-lightbox-close');
this.caption_container = this.container.querySelector('.annytab-lightbox-caption');
this.left_arrow = this.container.querySelector('.annytab-lightbox-left-arrow');
this.right_arrow = this.container.querySelector('.annytab-lightbox-right-arrow');
// Fade in the container
annytab.effects.fadeIn(this.container, this.options.fade_duration, 'block');
// Add container events
addContainerEvents(this);
// Show the next slide
this.showSlide(1);
}; // End of the open method
// Close a lightbox
lightbox.prototype.close = function () {
// Turn of the slideshow
clearInterval(this.automatic_slideshow);
// Fade out the container
annytab.effects.fadeOut(this.container, this.options.fade_duration);
// Remove the container
var box = this.container;
setTimeout(function ()
{
document.body.removeChild(box);
}, this.options.fade_duration);
// Reset variables (GC)
resetVariables(this);
}; // End of the close method
// Return this object
return lightbox;
})();
Så här använder du denna plugin
Lägg till en länk runt bilder som ska ha ett bildgalleri, ange ett data-lightbox-group attribut (valfritt) för bilder som ska ingå i en grupp och ange ett attribut för data-lightbox-caption (valfritt) om du vill att en bildtext ska visas över bilden. Vi har använt en klass som väljare (selector), det kan vara en klass, en tagg eller ett namn.
<a href="/images/background_large.jpg" class="annytab-lightbox-popup" data-lightbox-group="gp1" data-lightbox-caption="Hello, I am the one how have taken this photo.">
<img src="/images/background_small.jpg" alt="Background image" style="max-width:100%;border:1px solid #cccccc;" />
</a>
<a href="/images/logotype_large.jpg" class="annytab-lightbox-popup" data-lightbox-group="gp1">
<img src="/images/logotype_small.jpg" alt="Background image" style="max-width:100%;border:1px solid #cccccc;" />
</a>
@*Open and close from JavaScript*@
<div id="testLink" href="/images/background_large.jpg"></div>
<div onclick="openLink()">Open link</div>
<div style="position:absolute;z-index:500;font-size:36px;margin-top:50px;" onclick="closeBox()">Close box</div>
Skapa en ny instans av denna plugin inuti en skript-tagg och lägg till alternativ som en parameter. Bildgalleri läggs till för alla länkar med den valda väljaren, du kan manuellt anropa metoden open och metoden close från skript om du vill.
<script src="js/font-awesome/v5.3.1/all.min.js"></script>
<script src="/js/annytab-shared/annytab.effects.js"></script>
<script src="/js/annytab-shared/annytab.lightbox.js"></script>
<script>
// Lightbox
var lightbox = new annytab.lightbox({ selector: '.annytab-lightbox-popup', fade_duration: 1000, close_click_outside: true, slideshow: true, slideshow_interval: 10000 });
// Open lightbox
function openLink() { lightbox.open(document.getElementById('testLink')); }
// Close lightbox
function closeBox() { console.log('Closing'); lightbox.close(); }
</script>