Вот пример того, чего вы хотите достичь, используя Bootstrap 4, который, хотя и не включен в ваш вопрос, использовался в качестве тега вопроса, поэтому я предполагаю, что вы используете его или, по крайней мере, хотитеиспользуйте его:
С вкладками:
/* added for SO example only, you probably don't need it */
.nav.nav-tabs {
margin: 1rem 0;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<div class="container">
<ul class="nav nav-tabs" id="myTab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="slider-1-tab" data-toggle="tab" href="#slider-1" role="tab" aria-controls="slider-1" aria-selected="true">Slider 1</a>
</li>
<li class="nav-item">
<a class="nav-link" id="slider-2-tab" data-toggle="tab" href="#slider-2" role="tab" aria-controls="slider-2" aria-selected="false">Slider 2</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="slider-1" role="tabpanel" aria-labelledby="slider-1-tab">
<div id="carouselSlider-1" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#carouselSlider-1" data-slide-to="0" class="active"></li>
<li data-target="#carouselSlider-1" data-slide-to="1"></li>
<li data-target="#carouselSlider-1" data-slide-to="2"></li>
</ol>
<div class="carousel-inner">
<div class="carousel-item active">
<img class="d-block w-100" src="https://www.gstatic.com/webp/gallery/1.jpg" alt="First slide">
</div>
<div class="carousel-item">
<img class="d-block w-100" src="https://www.gstatic.com/webp/gallery/2.jpg" alt="Second slide">
</div>
<div class="carousel-item">
<img class="d-block w-100" src="https://www.gstatic.com/webp/gallery/3.jpg" alt="Third slide">
</div>
</div>
<a class="carousel-control-prev" href="#carouselSlider-1" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#carouselSlider-1" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
</div>
<div class="tab-pane" id="slider-2" role="tabpanel" aria-labelledby="slider-2-tab">
<div id="carouselSlider-2" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#carouselSlider-2" data-slide-to="0" class="active"></li>
<li data-target="#carouselSlider-2" data-slide-to="1"></li>
</ol>
<div class="carousel-inner">
<div class="carousel-item active">
<img class="d-block w-100" src="https://www.gstatic.com/webp/gallery/4.jpg" alt="First slide">
</div>
<div class="carousel-item">
<img class="d-block w-100" src="https://www.gstatic.com/webp/gallery/5.jpg" alt="Second slide">
</div>
</div>
<a class="carousel-control-prev" href="#carouselSlider-2" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#carouselSlider-2" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
</div>
</div>
</div>
Правда, это можно сделать умнее. У вас может быть объект конфигурации, содержащий структуру вашей галереи, и функцию, которая выводит необходимую разметку из вашего объекта.
Общий пример с вкладками и config
объектом:
Создает все вкладки + ползунки динамически, во время компиляции, с config
:
$(function() {
const galleryConfig = {
sliders: [{
id: 'slider-1',
title: 'Slider 1',
slides: [{
src: 'https://www.gstatic.com/webp/gallery/1.jpg',
alt: 'First slide'
}, {
src: 'https://www.gstatic.com/webp/gallery/2.jpg',
alt: 'Second slide'
}, {
src: 'https://www.gstatic.com/webp/gallery/3.jpg',
alt: 'Third slide'
}]
}, {
id: 'slider-2',
title: 'Slider 2',
slides: [{
src: 'https://www.gstatic.com/webp/gallery/4.jpg',
alt: 'First slide'
}, {
src: 'https://www.gstatic.com/webp/gallery/5.jpg',
alt: 'Second slide'
}]
}]
};
function generateSliders(config) {
let navs = $('<ul />', {
role: 'tablist',
class: 'nav nav-tabs'
});
let tabs = $('<div />', {
class: 'tab-content'
})
config.sliders.forEach((slider, index) => {
let $li = $('<li />', {
class: 'nav-item',
html: $('<a />', {
class: 'nav-link' + (index ? '' : ' active'),
id: `slider-${index + 1}-tab`,
'data-toggle': 'tab',
href: `#slider-${index + 1}`,
role: 'tab',
'aria-controls': `#slider-${index + 1}`,
'aria-selected': index ? 'false' : 'true',
text: slider.title
})
});
$li.appendTo(navs);
});
navs.appendTo($('#galleryContainer'));
config.sliders.forEach((slider, index) => {
let $tab = $('<div />', {
class: 'tab-pane' + (index ? '' : ' active'),
id: slider.id,
role: 'tabpanel',
'aria-labelledby': `${slider.id}-tab`,
html: $('<div />', {
class: 'carousel slide',
'data-ride': 'carousel',
id: `carouselSlider-${index + 1}`,
html: $('<ol />', {
class: 'carousel-indicators',
html: slider.slides.map((s, i) => $('<li />', {
'data-target': `#carouselSlider-${index + 1}`,
'data-slide-to': `${i}`,
class: i ? '' : 'active'
})[0].outerHTML).join('')
})[0].outerHTML
+ $('<div />', {
class: 'carousel-inner',
html: slider.slides.map((s, i) => $('<div />', {
class: 'carousel-item' + (i ? '' : ' active'),
html: $('<img />', {
class: 'd-block w-100',
src: s.src,
alt: s.alt
})
})[0].outerHTML).join('')
})[0].outerHTML
+ $('<a />', {
class: 'carousel-control-prev',
href: `#carouselSlider-${index + 1}`,
role: 'button',
'data-slide': 'prev',
html: $('<span />', {
class: 'carousel-control-prev-icon',
'aria-hidden': 'true'
})[0].outerHTML
+ $('<span />', {
class: 'sr-only',
text: 'Previous'
})[0].outerHTML
})[0].outerHTML
+ $('<a />', {
class: 'carousel-control-next',
href: `#carouselSlider-${index + 1}`,
role: 'button',
'data-slide': 'next',
html: $('<span />', {
class: 'carousel-control-next-icon',
'aria-hidden': 'true'
})[0].outerHTML
+ $('<span />', {
class: 'sr-only',
text: 'Next'
})[0].outerHTML
})[0].outerHTML
})
});
$tab.appendTo(tabs)
})
tabs.appendTo($('#galleryContainer'));
}
generateSliders(galleryConfig);
})
/* added for SO example only, you probably don't need it */
.nav.nav-tabs {
margin: 1rem 0;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<div class="container">
<div id="galleryContainer"></div>
</div>
Очевидно, ваш объект конфигурации может быть загружен из внешнего источника. Это просто доказательство концепции. generateSliders()
выполняет все ползунки в объекте config и выводит необходимую разметку Bootstrap 4, так что вам не нужно этого делать, тем более что атрибут aria легко пропустить и, IMHO, сделать это вручную следуетпо возможности избегать.
При модальных значениях:
.modal-launchers img {
width: 100px;
height: auto;
display: inline-block;
margin-right: 1rem;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<div class="container">
<div class="row">
<div class="col modal-launchers">
<a id="modal-link-1" href="#modal-1" data-toggle="modal" data-target="#modal-1">
<img src="https://www.gstatic.com/webp/gallery/1.jpg" alt="First slider">
</a>
<a id="modal-link-2" href="#modal-2" data-toggle="modal" data-target="#modal-2">
<img src="https://www.gstatic.com/webp/gallery/4.jpg" alt="Second slider"></a>
</div>
</div>
</div>
<div class="modal fade" id="modal-1" tabindex="-1" role="dialog" aria-labelledby="modal-link-1" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">First gallery</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div id="carouselSlider-1" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#carouselSlider-1" data-slide-to="0" class="active"></li>
<li data-target="#carouselSlider-1" data-slide-to="1"></li>
<li data-target="#carouselSlider-1" data-slide-to="2"></li>
</ol>
<div class="carousel-inner">
<div class="carousel-item active">
<img class="d-block w-100" src="https://www.gstatic.com/webp/gallery/1.jpg" alt="First slide">
</div>
<div class="carousel-item">
<img class="d-block w-100" src="https://www.gstatic.com/webp/gallery/2.jpg" alt="Second slide">
</div>
<div class="carousel-item">
<img class="d-block w-100" src="https://www.gstatic.com/webp/gallery/3.jpg" alt="Third slide">
</div>
</div>
<a class="carousel-control-prev" href="#carouselSlider-1" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#carouselSlider-1" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="modal-2" tabindex="-1" role="dialog" aria-labelledby="modal-link-2" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Second gallery</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div id="carouselSlider-2" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#carouselSlider-2" data-slide-to="0" class="active"></li>
<li data-target="#carouselSlider-2" data-slide-to="1"></li>
</ol>
<div class="carousel-inner">
<div class="carousel-item active">
<img class="d-block w-100" src="https://www.gstatic.com/webp/gallery/4.jpg" alt="First slide">
</div>
<div class="carousel-item">
<img class="d-block w-100" src="https://www.gstatic.com/webp/gallery/5.jpg" alt="Second slide">
</div>
</div>
<a class="carousel-control-prev" href="#carouselSlider-2" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#carouselSlider-2" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
</div>
</div>
</div>
</div>
Опять же, просто пример. Все, что вам нужно сделать, это перейти к документации Bootstrap, взять разметку из примера и применить ее к своему коду.
Общий пример с модалами и config
object:
Создает все модалы + ползунки динамически, во время компиляции, от config
:
$(function() {
const galleryConfig = {
sliders: [{
id: 'slider-1',
title: 'Slider 1',
slides: [{
src: 'https://picsum.photos/id/230/800/600',
alt: 'First slide'
}, {
src: 'https://picsum.photos/id/231/800/600',
alt: 'Second slide'
}, {
src: 'https://picsum.photos/id/232/800/600',
alt: 'Third slide'
}]
}, {
id: 'slider-2',
title: 'Slider 2',
slides: [{
src: 'https://picsum.photos/id/233/800/600',
alt: 'First slide'
}, {
src: 'https://picsum.photos/id/234/800/600',
alt: 'Second slide'
}, {
src: 'https://picsum.photos/id/235/800/600',
alt: 'Third slide'
}, {
src: 'https://picsum.photos/id/236/800/600',
alt: 'Fourth slide'
}, {
src: 'https://picsum.photos/id/237/800/600',
alt: 'Fifth slide'
}]
}]
};
function generateModals(config) {
let navs = $('#galleryContainer');
config.sliders.forEach((slider, i) => {
let $launcher = $('<a />', {
id: `modal-link-${i}`,
href: `#gallery-modal-${i}`,
'data-target': `#gallery-modal-${i}`,
'data-toggle': 'modal',
title: slider.title,
html: slider.slides.map(image => $('<img />', {
src: image.src,
alt: image.title
})).map(o => o[0].outerHTML).join('')
});
$launcher.appendTo(navs);
});
navs.appendTo($('#galleryContainer'));
config.sliders.forEach((slider, i) => {
let $modalDiv = $('<div />', {
class: 'modal fade',
id: `gallery-modal-${i}`,
role: 'dialog',
'aria-labelledby': `modal-link-${i}`,
'aria-hidden': 'true',
html: $('<div />', {
class: 'modal-dialog modal-lg',
role: 'document',
html: $('<div />', {
class: 'modal-content',
html: $('<div />', {
class: 'modal-header',
html: $('<h5 />', {
class: 'modal-title',
text: slider.title
})[0].outerHTML +
$('<button />', {
type: 'button',
class: 'close',
'data-dismiss': 'modal',
'aria-label': 'Close',
html: $('<span />', {
'aria-hidden': 'true',
html: '×'
})
})[0].outerHTML
})[0].outerHTML +
$('<div />', {
class: 'modal-body',
html: $('<div />', {
class: 'carousel slide',
'data-ride': 'carousel',
id: `carouselSlider-${i}`,
html: $('<ol />', {
class: 'carousel-indicators',
html: slider.slides.map((o, k) => $('<li />', {
'data-target': `#carouselSlider-${i}`,
'data-slide-to': `${k}`,
class: k ? '' : 'active'
})[0].outerHTML).join('')
})[0].outerHTML +
$('<div />', {
class: 'carousel-inner',
html: slider.slides.map((o, k) => $('<div />', {
class: 'carousel-item' + (k ? '' : ' active'),
html: $('<img />', {
class: 'd-block w-100',
src: o.src,
alt: o.alt
})
})[0].outerHTML).join('')
})[0].outerHTML +
$('<a />', {
class: 'carousel-control-prev',
href: `#carouselSlider-${i}`,
role: 'button',
'data-slide': 'prev',
html: $('<span />', {
class: 'carousel-control-prev-icon',
'aria-hidden': 'true'
})[0].outerHTML +
$('<span />', {
class: 'sr-only',
text: 'Previous'
})[0].outerHTML
})[0].outerHTML +
$('<a />', {
class: 'carousel-control-next',
href: `#carouselSlider-${i}`,
role: 'button',
'data-slide': 'next',
html: $('<span />', {
class: 'carousel-control-next-icon',
'aria-hidden': 'true'
})[0].outerHTML +
$('<span />', {
class: 'sr-only',
text: 'Next'
})[0].outerHTML
})[0].outerHTML
})
})[0].outerHTML
})
})
});
$modalDiv.appendTo($('body'))
})
}
generateModals(galleryConfig);
})
#galleryContainer img {
height: 72px;
width: auto;
display: block;
margin: 0 1px 1px 0;
}
#galleryContainer a {
margin: 0 0 -1px;
padding: .5rem;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
transition: background-color .3s ease-out;
background-color:transparent;
}
#galleryContainer a:hover {
background-color: #f5f5f5;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<div class="container">
<div class="row">
<div class="col">
<div id="galleryContainer"></div>
</div>
</div>
</div>