轮播图在平常的网页开发中十分常见,特别是电商类的网站。
前端 “进化” 到今天,组件化的思想早已深入人心。
组件库的出现更是提高了不少的开发效率。网上对于程序员是否需要重新造轮子一直还是有争论的。
但不管争论如何,该学的东西还是得学。毕竟面试需要,工资重要啊。
可以说只要是个组件库,就会有轮播图组件,也有单独做 swpier 的插件。你当然可以选择直接现成的轮子,也可以自己造一个(生活已经很累了,你为什么还要给我增加负担 )
卧槽,CSS 这么牛逼的吗?o( ̄▽ ̄)d,CSS yyds
基础版
<html lang="en">
<head>
<meta charset="utf-8">
<title>轮播图title>
<style>
* {
margin: 0;
padding: 0;
text-align: none;
}
/*设置显示图片的大小,溢出隐藏*/
.slidershow {
width: 800px;
height: 600px;
overflow: hidden;
}
/*居中*/
.middle {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/*实现块元素百分比下居中*/
}
/*导航 设置绝对位置,弹性布局,按钮位置*/
.navigaion {
position: absolute;
bottom: 5px;
/*底部距离*/
left: 50%;
transform: translateX(-50%);
display: flex;
}
/*设置按钮属性*/
.bar {
width: 50px;
height: 10px;
border: 2px solid #FFF8DC;
margin: 0.375rem;
cursor: pointer;
transition: 0.4s;
}
.bar:hover {
background-color: #FFF8DC;
}
/*隐藏了按钮*/
input[name="r"] {
position: absolute;
visibility: hidden;
}
/* 图片部分 */
.slides {
width: 1000%;
height: 100%;
display: flex;
}
.slide {
width: 10%;
transition: 1.5s;
}
.slide img {
width: 100%;
height: 100%;
}
/* 绑定按钮 */
/* radio 标签与 img 相关联 */
#r1:checked~.s1 {
margin-left: 0;
}
#r2:checked~.s1 {
margin-left: -10%;
}
#r3:checked~.s1 {
margin-left: -20%;
}
#r4:checked~.s1 {
margin-left: -30%;
}
style>
head>
<body>
<div class="slidershow middle">
<div class="slides">
<input type="radio" name="r" id="r1" checked/>
<input type="radio" name="r" id="r2" />
<input type="radio" name="r" id="r3" />
<input type="radio" name="r" id="r4" />
<div class="slide s1">
<img src="https://cdn.pixabay.com/photo/2020/09/20/10/08/mountain-5586606__340.jpg" alt="photo" />
div>
<div class="slide">
<img src="https://cdn.pixabay.com/photo/2020/09/11/17/01/landscape-5563684__340.jpg" alt="photo" />
div>
<div class="slide">
<img src="https://cdn.pixabay.com/photo/2020/09/23/15/10/street-5596262__340.jpg" alt="photo" />
div>
<div class="slide">
<img src="https://cdn.pixabay.com/photo/2020/09/24/18/00/man-5599377__340.jpg" alt="photo" />
div>
div>
<div class="navigaion">
<label for="r1" class="bar">label>
<label for="r2" class="bar">label>
<label for="r3" class="bar">label>
<label for="r4" class="bar">label>
div>
div>
body>
html>
进阶版
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<style>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
ul {
list-style: none;
}
img {
display: block;
max-width: 100%;
height: auto;
background-color: #ededed;
}
label {
display: block;
cursor: pointer;
}
a {
text-decoration: none;
color: inherit;
}
/* 将 radio 按钮移除至屏幕外 */
input[type="radio"] {
position: absolute;
bottom: 0;
left: -9999px;
}
body {
color: #fff;
margin: 20px 0;
font-family: sans-serif;
}
.container {
max-width: 450px;
padding: 0 20px;
margin: 0 auto;
}
.slidershow-wrapper {
position: relative;
}
/* 采用网格布局 */
.slidershow-wrapper .slidershow-list {
display: grid;
}
.slidershow-wrapper .slidershow-list li {
grid-column: 1;
grid-row: 1;
opacity: 0;
transition: opacity 0.25s;
}
/* 箭头样式 */
.slidershow-wrapper .arrows label::before,
.slidershow-wrapper .arrows label::after {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 40px;
height: 40px;
border-radius: 50%;
color: #000;
background-position: center;
background-repeat: no-repeat;
background-size: 24px 24px;
background-color: #fff;
opacity: 0.5;
transition: opacity 0.25s;
}
.slidershow-wrapper .arrows label::before {
left: 10px;
}
.slidershow-wrapper .arrows label::after {
right: 10px;
}
/* 设置小圆圈 */
.slidershow-wrapper .dots {
position: absolute;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
display: flex;
}
.slidershow-wrapper .dots li:not(:last-child) {
margin-right: 8px;
}
.slidershow-wrapper .dots label {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
border: 1px solid #fff;
transition: background 0.25s;
}
.slidershow-wrapper .dots label:hover {
background: currentColor;
}
/* 设置小圆圈 */
/* 缩略图布局 */
.thumb-list {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-column-gap: 20px;
margin-top: 20px;
}
.thumb-list label {
display: grid;
}
.thumb-list img,
.thumb-list .outer {
grid-column: 1;
grid-row: 1;
}
.thumb-list .outer {
display: grid;
place-items: center;
transition: background 0.25s;
}
.thumb-list .inner {
font-size: 18px;
opacity: 0;
transform: translateY(20px);
transition: all 0.25s;
}
/* 缩略图布局 */
[id="image1"]:checked~.container .slidershow-list li:nth-child(1),
[id="image2"]:checked~.container .slidershow-list li:nth-child(2),
[id="image3"]:checked~.container .slidershow-list li:nth-child(3),
[id^="image"]:checked~.container .arrows [for^="image"]:hover::before,
[id^="image"]:checked~.container .arrows [for^="image"]:hover::after {
opacity: 1;
}
[id="image1"]:checked~.container .arrows [for="image3"]::before,
[id="image2"]:checked~.container .arrows [for="image1"]::before,
[id="image3"]:checked~.container .arrows [for="image2"]::before {
content: '';
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/162656/arrow-prev-slideshow.svg);
}
[id="image1"]:checked~.container .arrows [for="image2"]::after,
[id="image2"]:checked~.container .arrows [for="image3"]::after,
[id="image3"]:checked~.container .arrows [for="image1"]::after {
content: '';
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/162656/arrow-next-slideshow.svg);
}
[id="image1"]:checked~.container .dots [for="image1"],
[id="image2"]:checked~.container .dots [for="image2"],
[id="image3"]:checked~.container .dots [for="image3"] {
background: currentColor;
}
[id="image1"]:checked~.container [for="image1"] .outer,
[id="image2"]:checked~.container [for="image2"] .outer,
[id="image3"]:checked~.container [for="image3"] .outer {
background: rgba(0, 0, 0, 0.75);
}
[id="image1"]:checked~.container [for="image1"] .inner,
[id="image2"]:checked~.container [for="image2"] .inner,
[id="image3"]:checked~.container [for="image3"] .inner {
opacity: 1;
transform: none;
}
style>
head>
<body>
<input type="radio" id="image1" name="image" checked>
<input type="radio" id="image2" name="image">
<input type="radio" id="image3" name="image">
<div class="container">
<div class="slidershow-wrapper">
<ul class="slidershow-list">
<li>
<figure>
<img src="https://cdn.pixabay.com/photo/2020/09/20/10/08/mountain-5586606__340.jpg" alt="">
figure>
li>
<li>
<figure>
<img src="https://cdn.pixabay.com/photo/2020/09/11/17/01/landscape-5563684__340.jpg" alt="">
figure>
li>
<li>
<figure>
<img src="https://cdn.pixabay.com/photo/2020/09/23/15/10/street-5596262__340.jpg" alt="">
figure>
li>
ul>
<ul class="arrows">
<li>
<label for="image1">label>
li>
<li>
<label for="image2">label>
li>
<li>
<label for="image3">label>
li>
ul>
<ul class="dots">
<li>
<label for="image1">label>
li>
<li>
<label for="image2">label>
li>
<li>
<label for="image3">label>
li>
ul>
div>
<ul class="thumb-list">
<li>
<label for="image1">
<img src="https://cdn.pixabay.com/photo/2020/09/20/10/08/mountain-5586606__340.jpg" alt="">
<span class="outer">
<span class="inner"> Caption1 span>
span>
label>
li>
<li>
<label for="image2">
<img src="https://cdn.pixabay.com/photo/2020/09/11/17/01/landscape-5563684__340.jpg" alt="">
<span class="outer">
<span class="inner"> Caption2 span>
span>
label>
li>
<li>
<label for="image3">
<img src="https://cdn.pixabay.com/photo/2020/09/23/15/10/street-5596262__340.jpg" alt="">
<span class="outer">
<span class="inner">Caption3 span>
span>
label>
li>
ul>
div>
body>
html>
小声BB:忘记了代码的原地址,有知道的告诉我一声,我附上
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0 user-scalable=0">
<title>Documenttitle>
<style>
* {
margin: 0;
padding: 0;
touch-action: pan-y;
}
html,
body {
height: 100%;
overflow: hidden;
}
#wrap {
height: 100%;
overflow: hidden;
}
.carousel-wrap {
position: relative;
overflow: hidden;
}
.carousel-wrap>.list {
list-style: none;
overflow: hidden;
position: absolute;
}
.carousel-wrap>.list>li>a,
.carousel-wrap>.list>li>a>img {
display: block;
}
.carousel-wrap>.list>li>a>img {
width: 100%;
}
.carousel-wrap>.list>li {
float: left;
}
.carousel-wrap>.list {
overflow: hidden;
}
.carousel-wrap>.points-wrap {
position: absolute;
bottom: 0;
width: 100%;
text-align: center;
z-index: 1;
}
.carousel-wrap>.points-wrap>span {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #000;
display: inline-block;
margin-left: 5px;
}
.carousel-wrap>.points-wrap>span.active {
background-color: #fff;
}
style>
head>
<body>
<div id="wrap">
<div class="carousel-wrap" needCarousel needAuto>
<div class="points-wrap">div>
div>
div>
<script>
(function (w) {
// w => window
w.swiper = {}
w.swiper.css = function css(node, type, val) {
if (node && typeof node["transform"] === "undefined") {
node["transform"] = {}
}
if (arguments.length >= 3) {
var text = ""
node["transform"][type] = val
for (item in node["transform"]) {
if (node["transform"].hasOwnProperty(item)) {
switch (item) {
case "translateX":
case "translateY":
text += item + "(" + node["transform"][item] + "px)"
break;
case "scale":
text += item + "(" + node["transform"][item] + ")"
break;
case "rotate":
text += item + "(" + node["transform"][item] + "deg)"
break;
}
}
}
node.style.transform = node.style.webkitTransform = text
} else if (arguments.length === 2) {
val = node["transform"][type]
if (typeof val === "undefined") {
switch (type) {
case "translateX":
case "translateY":
case "rotate":
val = 0
case "scale":
val = 1
break;
}
}
return val
}
}
w.swiper.carousel = function carousel(arr) {
// 创建布局
var carouselWrap = document.querySelector('.carousel-wrap')
//
if (carouselWrap) {
// 获取图片数组的长度
var pointslength = arr.length
// 判断该元素是否需要轮播
var needCarousel = carouselWrap.getAttribute("needCarousel")
needCarousel = needCarousel === null ? false : true
// 连接数组
if (needCarousel) {
arr = arr.concat(arr)
}
// 创建下方的小圆点
var ulNode = document.createElement('ul')
var styleNode = document.createElement('style')
// ul 添加样式
ulNode.classList.add('list')
// 根据 arr 的长度生成 img 标签
for (let i = 0; i < arr.length; i++) {
ulNode.innerHTML += `
${arr[i]} " alt="">
`
}
// 生成 li 的宽度
styleNode.innerHTML = `.carousel-wrap>.list>li {width: ${1 / arr.length * 100}%;}
.carousel-wrap>.list {width: ${arr.length}00%;}`
// 加入页面中
carouselWrap.appendChild(ulNode)
document.head.appendChild(styleNode)
var imgNodes = document.querySelector('.carousel-wrap>.list>li>a>img')
// 图片撑满容器
setTimeout(function () {
carouselWrap.style.height = imgNodes.offsetHeight + 'px'
}, 100)
var pointsWrap = document.querySelector('.carousel-wrap > .points-wrap')
// 根据小圆点数组的长度,往页面当中插入小圆点。如果是第一个,那默认为选中。
if (pointsWrap) {
for (let i = 0; i < pointslength; i++) {
if (i === 0) {
pointsWrap.innerHTML += ``
} else {
pointsWrap.innerHTML += ``
}
}
// 小圆点
var pointsSpan = document.querySelectorAll('.carousel-wrap > .points-wrap > span')
}
// 滑动布局
var index = 0
// 手指的位置
var startX = 0
// 元素的位置
var elementX = 0
var disX = 0
// 监听 touchstart 事件
carouselWrap.addEventListener('touchstart', function (ev) {
ev = ev || event
var TouchC = ev.changedTouches[0]
ulNode.style.transition = 'none'
// 无缝逻辑(点击第一组第一张,瞬间调到第二组第一张)
// (点击第二组最后一张,瞬间调到第一组最后一张)
if (needCarousel) {
var index = swiper.css(ulNode, "translateX") / document.documentElement.clientWidth
if (-index === 0) {
index = -pointslength
} else if (-index === (arr.length - 1)) {
index = -(pointslength - 1)
}
swiper.css(ulNode, "translate", index * document.documentElement.clientWidth)
}
startX = TouchC.clientX
// elementX = translateX
elementX = swiper.css(ulNode, "translateX")
// 清除定时器
clearInterval(timer)
}, { passive: false })
// 监听 touchmove 事件
carouselWrap.addEventListener('touchmove', function (ev) {
ev = ev || event
var TouchC = ev.changedTouches[0]
var nowX = TouchC.clientX
var disX = nowX - startX
swiper.css(ulNode, "translateX", elementX + disX)
}, { passive: false })
// 监听 touchend 事件
carouselWrap.addEventListener('touchend', function (ev) {
ev = ev || event
// index 代表窗口 ul 的实时位置
index = swiper.css(ulNode, "translateX") / document.documentElement.clientWidth
index = Math.round(index)
// 超出控制
if (index > 0) {
index = 0
} else if (index < 1 - arr.length) {
index = 1 - arr.length
}
dots(index)
ulNode.style.transition = '1s transform'
swiper.css(ulNode, "translateX", index * (document.documentElement.clientWidth))
// 开启自动轮播
if (needAuto) {
auto()
}
}, { passive: false })
var timer = 0
// 抽象图片下标
var needAuto = carouselWrap.getAttribute("needAuto")
needAuto = needAuto === null ? false : true
// 自动轮播
if (needAuto) {
auto()
}
function auto() {
clearInterval(timer)
timer = setInterval(function () {
if (index === 1 - arr.length) {
ulNode.style.transition = "none"
index = 1 - arr.length / 2
swiper.css(ulNode, "translateX", index * document.documentElement.clientWidth)
}
setTimeout(function () {
index--
ulNode.style.transition = "1s transform"
dots(index)
swiper.css(ulNode, "translateX", index * document.documentElement.clientWidth)
}, 50)
}, 2000)
}
function dots(index) {
if (!pointsWrap) {
return
}
for (var i = 0; i < pointsSpan.length; i++) {
pointsSpan[i].classList.remove('active')
}
pointsSpan[-index % pointslength].classList.add('active')
}
}
}
})(window)
script>
<script>
window.onload = function () {
document.addEventListener('touchstart', function (ev) {
ev = ev || event
ev.preventDefault()
});
let arr = [
'https://cdn.pixabay.com/photo/2013/07/18/20/26/sea-164989__480.jpg',
'https://cdn.pixabay.com/photo/2013/07/25/01/31/forest-166733__340.jpg',
'https://cdn.pixabay.com/photo/2014/10/07/13/48/mountain-477832__340.jpg',
'https://cdn.pixabay.com/photo/2015/03/28/16/40/lake-696098__340.jpg',
'https://cdn.pixabay.com/photo/2016/10/18/21/22/beach-1751455__340.jpg'
]
swiper.carousel(arr)
}
script>
body>
html>
怎么说呢,现在这个 Vue,React, Angular 框架的时代,用 jQuery多少有点看不起这三个框架。
狗头保命
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
<script src="./jq.js">script>
<style>
a,
ul,
li {
list-style: none;
text-decoration: none;
margin: 0;
padding: 0;
}
.wrap {
width: 600px;
height: 400px;
margin: 100px auto;
position: relative;
overflow: hidden;
}
.navs {
width: 4200px;
height: 100%;
position: absolute;
top: 0;
left: -600px;
}
.navs li {
width: 600px;
height: 100%;
float: left;
}
.navs li img {
width: 100%;
height: 100%;
}
#bots {
display: inline-block;
width: 600px;
height: 40px;
background: rgba(66, 57, 57, 0.3);
text-align: center;
position: absolute;
bottom: 0;
left: 0;
}
#bots li {
width: 15px;
height: 15px;
border-radius: 50%;
background: #fff;
position: relative;
left: 220px;
top: 10px;
margin-left: 10px;
float: left;
}
#bots .active {
background: #000;
}
style>
head>
<body>
<div class="wrap" id="box">
<ul id='navs' class="navs">
<li><img src="https://cdn.pixabay.com/photo/2016/10/18/21/22/beach-1751455__340.jpg" />li>
<li><img src="https://cdn.pixabay.com/photo/2013/07/18/20/26/sea-164989__480.jpg" />li>
<li><img src="https://cdn.pixabay.com/photo/2013/07/25/01/31/forest-166733__340.jpg" />li>
<li><img src="https://cdn.pixabay.com/photo/2014/10/07/13/48/mountain-477832__340.jpg" />li>
<li><img src="https://cdn.pixabay.com/photo/2015/03/28/16/40/lake-696098__340.jpg" />li>
<li><img src="https://cdn.pixabay.com/photo/2016/10/18/21/22/beach-1751455__340.jpg" />li>
<li><img src="https://cdn.pixabay.com/photo/2013/07/18/20/26/sea-164989__480.jpg" />li>
ul>
<ul id="bots">
<li class="bot active">li>
<li class="bot">li>
<li class="bot">li>
<li class="bot">li>
<li class="bot">li>
ul>
div>
<script>
// 1.图片不断出现/隐藏 不断向左侧移动
// 2.对应的小圆点背景颜色变红
let num = 1;
let i = 0;
let timer = null;
swiper();
// 把定时器功能做一个函数封装
function swiper() {
timer = setInterval(() => {
// 1、图片功能
num++;
// 设置条件 当num大于6,num=2
if (num > 6) {
// num = 6的时候,其实显示 ban1
// 应该通过样式赋值的形式,直接变为 真正的 ban1
$("#navs").css('left', -600)
num = 2;
}
$("#navs").animate({ left: -num * 600 }, 500);
// 2.小圆点功能
i++;
if (i > 4) {
i = 0;
}
$("#bots li").eq(i).addClass('active').siblings().removeClass('active');
}, 2000);
}
// 鼠标移入 清除定时器
$(".wrap").mouseover(() => {
clearInterval(timer);
});
// 鼠标移出 开启定时器
$(".wrap").mouseout(() => {
swiper();
});
script>
body>
html>
实现效果如下
写之前我们需要安装
npm install better-scroll
slider.vue
<template>
<div class="slider" ref="slider">
<div class="slider-group" ref="sliderGroup">
<slot>
</slot>
</div>
<div class="dots">
<span
class="dot"
v-for="(item, index) in dots"
:key="index"
:class="{active: currentPageIndex === index}"
></span>
</div>
</div>
</template>
<script>
import BScroll from 'better-scroll'
import { addClass } from '../../common/js/dom'
export default {
data() {
return {
dots: [],
currentPageIndex: 0
}
},
props: {
loop: {
type: Boolean,
default: true
},
autoPlay: {
type: Boolean,
default: true
},
interval: {
type: Number,
default: 4000
}
},
mounted() {
setTimeout(() => {
this._setSliderWidth()
this._initDots()
this._initSlider()
if (this.autoPlay) {
this._play()
}
}, 20)
window.addEventListener('resize', () => {
if (!this.slider) {
return
}
this._setSliderWidth(true)
this.slider.refresh()
})
},
methods: {
_setSliderWidth(isResize) {
this.children = this.$refs.sliderGroup.children
let width = 0
let slideWidth = this.$refs.slider.clientWidth
for (let i = 0; i < this.children.length; i++) {
let children = this.children[i]
addClass(children, 'slider-item')
children.style.width = slideWidth + 'px'
width += slideWidth
}
if (this.loop && !isResize) {
width += 2 * slideWidth
}
this.$refs.sliderGroup.style.width = width + 'px'
},
_initSlider() {
this.slider = new BScroll(this.$refs.slider, {
scrollX: true,
scrollY: false,
momentum: false,
snap: true,
snapLoop: this.loop,
snapThreshold: 0.3,
snapSpeed: 400
})
this.slider.on('scrollEnd', () => {
let pageIndex = this.slider.getCurrentPage().pageX
if (this.loop) {
pageIndex -= 1
}
this.currentPageIndex = pageIndex
if (this.autoPlay) {
clearTimeout(this.timer)
this._play()
}
})
},
_initDots() {
this.dots = new Array(this.children.length)
},
_play() {
let pageIndex = this.currentPageIndex + 1
if (this.loop) {
pageIndex += 1
}
this.timer = setTimeout(() => {
this.slider.goToPage(pageIndex, 0, 400)
}, this.interval)
}
},
destroyed() {
clearTimeout(this.timer)
}
}
</script>
<style scoped lang="stylus">
.slider
min-height: 1px
.slider-group
position: relative
overflow: hidden
white-space: nowrap
.slider-item
float: left
box-sizing: border-box
overflow: hidden
text-align: center
height 200px
.a
display: block
width: 100%
overflow: hidden
text-decoration: none
img
display: block
width: 100%
.dots
position: absolute
right: 0
left: 0
bottom: 12px
text-align: center
font-size: 0
.dot
display: inline-block
margin: 0 4px
width: 8px
height: 8px
border-radius: 50%
background: rgba(255, 255, 255, 0.5)
&.active
width: 20px
border-radius: 5px
background: rgba(255, 255, 255, 0.8)
</style>
dom.js
export function addClass(el, className) {
if (hasClass(el, className)) {
return
}
let newClass = el.className.split(' ')
newClass.push(className)
el.className = newClass.join(' ')
}
export function hasClass(el, className) {
let reg = new RegExp('(^|\\s)' + className + '(\\s|$)')
return reg.test(el.className)
}
export function getData(el, name, val) {
const prefix = 'data-'
name = prefix + name
if (val) {
return el.setAttribute(name, val)
} else {
return el.getAttribute(name)
}
}
使用方法
<div v-if="recommends.length" class="slider-wrapper">
<Slider>
<div v-for="item in recommends" :key="item.linkUrl">
<router-link :to="item.linkUrl" class="a">
<img
@load="loadImage"
v-lazy="item.picUrl"
width="100%"
height="200"
>
</router-link>
</div>
</Slider>
</div>
import Slider from '../../base/slider/slider'
data() {
return {
recommends: [
{
"picUrl": "https://cdn.pixabay.com/photo/2020/08/11/13/28/flowers-5479950__340.jpg",
"linkUrl": '/'
},
{
"picUrl": "https://cdn.pixabay.com/photo/2020/08/08/20/19/wave-5473869__340.jpg",
"linkUrl": '/a'
},
{
"picUrl": "https://cdn.pixabay.com/photo/2020/07/05/12/53/rainbow-5372892__340.jpg",
"linkUrl": '/b'
}
]
}
},
components: {
Slider
},
methods: {
loadImage() {
if (!this.checkloaded) {
this.checkloaded = true
this.$refs.scroll.refresh()
}
}
}
style
.slider-wrapper
position: relative
width: 100%
overflow: hidden
height 200px
最开始传入图片数据
import Banner from './banner'
let imgUrl = [
'https://img.zcool.cn/community/010c815e25a8c4a801216518dcc1d4.jpg@1280w_1l_2o_100sh.jpg', 'https://img.zcool.cn/community/0189905e25a8c6a80120a89533cc7f.jpg@1280w_1l_2o_100sh.jpg', 'https://img.zcool.cn/community/01747f5e25a8c9a801216518193452.jpg@1280w_1l_2o_100sh.jpg', 'https://img.zcool.cn/community/01cbba5e25a8cea80120a895743281.jpg@1280w_1l_2o_100sh.jpg', 'https://img.zcool.cn/community/0186025e25a8d3a80121651827af9c.jpg@1280w_1l_2o_100sh.jpg'
]
function App() {
return (
<div>
<Banner
imgUrl={imgUrl}
/>
</div>
);
}
export default App;
基础架构:中间展示图片,两边箭头,下面依据图片数量生成的小圆点
import React from "react"
import "./banner.css"
export default class Banner extends React.Component {
render() {
return (
<div
className="container"
>
<div className="swiper-box">
{
this.props.imgUrl.map((item, index) => {
return (
<div className="swiper-item" key={index}>
<img src={item} alt="" />
</div>
)
})
}
</div>
<div className="swiper-arrow">
<div className="arrowLeft iconfont iconqianjin1"></div>
<div className="arrowRight iconfont iconqianjin"></div>
</div>
<div className="focus">
{
this.props.imgUrl.map((item, index) => {
return (
<div></div>
)
})
}
</div>
</div>
)
}
}
咦咦咦咦~~~~,so ugly
为实现无缝衔接轮播,我们需要重新去生成一份数组。props
中解构出 imgUrl
。
constructor(props) {
super(props)
let { imgUrl } = this.props
let imgUrlClone = []
imgUrlClone = imgUrlClone.concat([], imgUrl)
imgUrlClone.push(imgUrl[0])
imgUrlClone.unshift(imgUrl[imgUrl.length - 1])
console.log(imgUrlClone)
}
一顿操作下来,假设 imgUrl = [A, B, C, D, E]
=> imgUrlClone = [E, A, B, C, D, E, A]
{
this.imgUrlClone.map((item, index) => {
return (
<div className="swiper-item" key={index}>
<img src={item} alt="" />
</div>
)
})
}
接下来,要将图片的显示变为正常样式
let { width, height, step, speed } = this.state;
let swiperBoxStyle = {
width: `${this.imgUrlClone.length * width}px`,
left: `${-step * width}px`,
height: height + "px",
transition: `all ${speed}ms linear`
}
let commom = {
width: width + "px",
height: height + "px"
}
分别加到 className="container"
和 className="swiper-box"
上。
静态布局结束之后,让我们的图片动起来。
this.state = { speed, step, width, height }
componentDidMount() {
if (this.props.autoplay) {
this.timer = setInterval(() => {
this.next()
}, this.props.interval);
}
}
next = () => {
let { step } = this.state
if (step >= this.imgUrlClone.length - 1) {
this.setState({
step: 1,
speed: 0
})
}
setTimeout(() => {
this.setState({
step: this.state.step + 1,
speed: this.props.speed
})
}, 0)
}
切换小圆点对应的 active
样式
<div className="focus">
{
this.props.imgUrl.map((item, index) => {
if (step === this.imgUrlClone.length - 1) {
step = 1
}
if (step === 0) {
step = this.imgUrlClone.length - 2
}
return (
<div className={index + 1 === step ? "active" : ""} key={index}></div>
)
})
}
</div>
为左右箭头添加事件
<div className="swiper-arrow">
<div className="arrowLeft iconfont iconqianjin1" onClick={this.prev}>div>
<div className="arrowRight iconfont iconqianjin" onClick={this.next}>div>
div>
prev = () => {
let { step } = this.state
if (step <= 0) {
this.setState({
step: this.imgUrlClone.length - 2,
speed: 0
})
}
setTimeout(() => {
this.setState({
step: this.state.step - 1,
speed: this.props.speed
})
}, 0)
}
锦上添花,鼠标移入,轮播停止。鼠标移出,轮播继续
<div
className="container"
style={commom}
onMouseEnter={this.removeInte}
onMouseLeave={this.addInter}
>div>
removeInte = () => {
clearInterval(this.timer)
}
addInter = () => {
if (!this.props.autoplay) return
this.timer = setInterval(() => {
this.next()
}, this.props.interval);
}
源代码:React 轮播图组件