最近一直在研究Bootstrap5的前端开发,看bootstrap例子的时候发现了一个好的模型,所以就手痒给自己写了一个
PC端
移动端
先简单的介绍一些吧,支持移动端和PC端的拖动且由最后一张图切到第一张图的时候是平滑过渡,不会在掉头过渡
OK,下面那直接放代码,切记如果要直接用的话注意要在头部加一个Bootstrap5的CSS代码引入
<div class="slider">
<div class="slider-indicators">
<button class="active" data-to="0" tabindex="-1"></button>
<button data-to="1" tabindex="-1"></button>
<button data-to="2" tabindex="-1"></button>
</div>
<div class="slider-outer">
<div class="slider-inner">
<div class="slider-item">
<a href="">
<img src="https://around.createx.studio/img/demo/food-blog/videos/03.jpg" loading="lazy">
<span>Gallery video caption</span>
</a>
</div>
<div class="slider-item">
<a href="">
<img src="https://around.createx.studio/img/demo/food-blog/videos/01.jpg" loading="lazy">
<span>Gallery video caption</span>
</a>
</div>
<div class="slider-item">
<a href="">
<img src="https://around.createx.studio/img/demo/food-blog/videos/02.jpg" loading="lazy">
<span>Gallery video caption</span>
</a>
</div>
<div class="slider-item">
<a href="#">
<img src="https://around.createx.studio/img/demo/food-blog/videos/03.jpg" loading="lazy">
<span>Gallery video caption</span>
</a>
</div>
<div class="slider-item">
<a href="#">
<img src="https://around.createx.studio/img/demo/food-blog/videos/01.jpg" loading="lazy">
<span>Gallery video caption</span>
</a>
</div>
</div>
</div>
</div>
CSS代码
.slider{
position: relative;
}
.slider .slider-indicators{
position: absolute;
top: 100%;
width: 100%;
padding-top: 1rem;
text-align: center;
white-space: nowrap;
}
[data-to] {
display: inline-block;
position: relative;
width: .75rem;
height: .75rem;
margin: 0 .25rem;
padding: 0;
border: 0;
background: none;
outline: none;
}
[data-to].active:before{
opacity: 0;
}
[data-to]:before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: .375rem;
height: .375rem;
margin-top: -.1875rem;
margin-left: -.1875rem;
border-radius: 50%;
background-color: var(--bs-indigo);
transition: .2s ease-in-out;
}
[data-to]:after {
content: '';
position: absolute;
top: 0;
left: 0;
width: .75rem;
height: .75rem;
border: .125rem solid var(--bs-indigo);
border-radius: 50%;
opacity: 0;
transform: scale(.5);
transition: .2s ease-in-out;
}
[data-to].active:after {
opacity: 1;
transform: scale(1);
}
.slider .slider-outer{
position: relative;
overflow: hidden;
}
.slider-outer .slider-inner{
display: flex;
cursor: grab;
cursor: -webkit-grab;
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
-moz-user-select: none;
transform: translate3d(-50%, 0, 0);
}
.slider-inner .slider-item{
width: 50%;
flex-shrink: 0;
padding-right: 30px;
}
@media (max-width: 767.98px){
.slider-outer .slider-inner{
transform: translate3d(-100%, 0, 0);
margin-right: -16px;
}
.slider-inner .slider-item{
width: 100%;
padding-right: 16px;
}
}
.slider-item a{
display: block;
position: relative;
width: 100%;
border-radius: 1rem;
overflow: hidden;
}
.slider-item a:before {
content: '';
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(55,56,78,.55);
opacity: 0;
transition: opacity .3s ease-in-out;
}
.slider-item a:hover:before{
opacity: 1;
}
.slider-item a > img{
display: block;
width: 100%;
}
.slider-item a > span {
display: block;
position: absolute;
left: 0;
bottom: 0;
width: 100%;
padding: 1rem .5rem;
color: white;
font-size: .875rem;
text-align: center;
opacity: 0;
transform: translateY(0.5rem);
transition: .3s ease-in-out;
}
.slider-item a:hover > span{
transform: none;
opacity: 1;
}
JS代码,代码也就100来行,所以就没有封装
/* 滑动图 */
var dotsContainer = document.getElementsByClassName("slider-indicators")[0];
var dots = dotsContainer.getElementsByTagName("button");
var slideContainer = document.querySelector(".slider-inner");
var sliderItem = slideContainer.querySelectorAll(".slider-item");
var sliderItemNum = sliderItem.length;
var sliderItemWidth = sliderItem[0].offsetWidth;
let slideIndex = 1, moveDistant = 0, currentOffset;
let isMouseDown = false;
let isSlideDrag = false;
//小点被点击
for (let dot of dots) {
dot.onclick = function(e) {
slideIndex = Number(e.target.dataset.to) + 1;
slide();
}
}
//PC端——拖动移动图片
slideContainer.parentNode.onmousedown = function(e) {
isMouseDown = true;
moveDistant = e.clientX;
currentOffset = slideIndex * sliderItemWidth;
}
slideContainer.parentNode.onmousemove= function(e) {
if(isMouseDown){
isSlideDrag = true;
slideContainer.style.transform = "translate3d(-"+ (currentOffset+moveDistant-e.clientX) +"px, 0, 0)";
}
}
slideContainer.parentNode.onmouseup = function(e) {
isMouseDown = false;
isSlideDrag = false;
if(e.clientX - moveDistant < -60){//next
slideIndex++;
if(slideIndex > sliderItemNum - 2){
slideIndex = 1;
slideContainer.style.transform = "translate3d(0, 0, 0)";
slideContainer.style.transition = "0s";
setTimeout(slide, 15);
return;
}
slide();
}else if (e.clientX - moveDistant > 60) {//prev
slideIndex--;
if(slideIndex == 0){
dotsContainer.querySelector("button.active").classList.remove("active");
dots[sliderItemNum - 3].classList.add("active");
slideContainer.style.transform = "translate3d(-"+(slideIndex*sliderItemWidth)+"px, 0, 0)";
slideContainer.style.transition = "all .3s";
return;
}else if (slideIndex < 0) {
slideIndex = sliderItemNum - 3;
slideContainer.style.transform = "translate3d(-"+((slideIndex+1)*sliderItemWidth)+"px, 0, 0)";
slideContainer.style.transition = "0s";
setTimeout(slide, 15);
return;
}
slide();
}else {
slide();
}
}
//滑动效果
function slide() {
dotsContainer.querySelector("button.active").classList.remove("active");
dots[slideIndex - 1].classList.add("active");
slideContainer.style.transform = "translate3d(-"+ (slideIndex*sliderItemWidth) +"px, 0, 0)";
slideContainer.style.transition = "all .3s";
}
//避免超链接影响拖动
let slideLinks = slideContainer.querySelectorAll(".slider-item > a");
for (let slideLink of slideLinks) {
slideLink.ondragstart = function(e) {
e.preventDefault();
}
slideLink.onclick = function() {
if(isSlideDrag){
e.preventDefault();
}
}
}
//移动端拖动
slideContainer.parentNode.ontouchstart = function(e) {
isMouseDown = true;
moveDistant = e.touches[0].clientX;
currentOffset = slideIndex * sliderItemWidth;
}
slideContainer.parentNode.ontouchmove= function(e) {
if(isMouseDown){
e.preventDefault();
isSlideDrag = true;
slideContainer.style.transform = "translate3d(-"+ (currentOffset+moveDistant-e.touches[0].clientX) +"px, 0, 0)";
}
}
slideContainer.parentNode.ontouchend = function(e) {
isMouseDown = false;
isSlideDrag = false;
if(e.changedTouches[0].clientX - moveDistant < -60){//next
slideIndex++;
if(slideIndex > sliderItemNum - 2){
slideIndex = 1;
slideContainer.style.transform = "translate3d(0, 0, 0)";
slideContainer.style.transition = "0s";
setTimeout(slide, 15);
return;
}
slide();
}else if (e.changedTouches[0].clientX - moveDistant > 60) {//prev
slideIndex--;
if(slideIndex == 0){
dotsContainer.querySelector("button.active").classList.remove("active");
dots[sliderItemNum - 3].classList.add("active");
slideContainer.style.transform = "translate3d(-"+(slideIndex*sliderItemWidth)+"px, 0, 0)";
slideContainer.style.transition = "all .3s";
return;
}else if (slideIndex < 0) {
slideIndex = sliderItemNum - 3;
slideContainer.style.transform = "translate3d(-"+((slideIndex+1)*sliderItemWidth)+"px, 0, 0)";
slideContainer.style.transition = "0s";
setTimeout(slide, 15);
return;
}
slide();
}else {
slide();
}
}