三、移动端轮播图的实现
布局
<div id="app">
<div id="swiper-container">
<!-- 幻灯片的结构 -->
<div class="swiper-wrapper">
<div class="swiper-slide"><img src="./img/1.jpg"></div>
<div class="swiper-slide"><img src="./img/2.jpg"></div>
<div class="swiper-slide"><img src="./img/3.jpg"></div>
<div class="swiper-slide"><img src="./img/4.jpg"></div>
<div class="swiper-slide"><img src="./img/5.jpg"></div>
</div>
<!-- 导航点 -->
<div class="swiper-pagination">
<span class="active"></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</div>
</div>* {
margin: 0;
padding: 0;
}
ul {
list-style: none;
}
html,
body,
#app {
width: 100%;
height: 100%;
overflow: hidden;
}
#swiper-container{
width: 100%;
height: 176px; /* no */
position: relative;
.swiper-wrapper{
width: 500%;
overflow: hidden;
.swiper-slide{
width: 20%;
float: left;
img{
width: 100%;
display: block;
}
}
}
// 导航点
.swiper-pagination{
position: absolute;
width: 100%;
height: 10px; /* no */
left:0;
bottom: 10px; /* no */
line-height: 10px;
text-align: center;
span{
display: inline-block;
width: 10px; /* no */
height: 10px; /* no */
background: #fff;
border-radius: 50%;
margin-right: 4px;
}
.active{
background: darkorange;
}
}
}可拖拽
为包裹图片的容器开启定位
.swiper-wrapper {
position: absolute;
}接下来使用js动态改变这个容器的位置即可。
const app = document.querySelector('#app')
const container = document.querySelector('#swiper-container')
const wrapper = container.querySelector('.swiper-wrapper')
app.addEventListener('touchstart', function (e) {
e.preventDefault()
})
// 触摸开始事件
container.addEventListener('touchstart', function (e) {
// 获取触摸开始时的触点位置
this.x = e.touches[0].clientX
// 获取包裹元素的水平偏移量
this.left = wrapper.offsetLeft
})
// 触摸滑动时事件
container.addEventListener('touchmove', function (e) {
this._x = e.touches[0].clientX
// 计算新的left值
const newLeft = this._x - this.x + this.left
// 设置left的值
wrapper.style.left = newLeft + 'px'
})拖拽切换
向左划动切换右边的一张图片,向右滑动切换左边的一张图片。
// 获取图片的数量
const len = container.querySelectorAll('.swiper-slide')
// 当前显示的图片的下标
let index = 0
// 获取所有小圆点
const dots = container.querySelectorAll('.swiper-pagination span')
// 触摸结束事件
container.addEventListener('touchend', function (e) {
// 获取触点结束时触点位置
this._x = e.changedTouches[0].clientX
// 向左滑动
if (this._x < this.x) {
index++
}
// 向右滑动
if (this._x > this.x) {
index--
}
// 检测是否越界
if (index < 0) {
index = 0
}
if (index > len.length - 1) {
index = len.length - 1
}
/**
* index => left
* 0 => 0
* 1 => index * -375
*/
// 计算新的left的值
const newLeft = -index * container.offsetWidth
// 设置left的样式
wrapper.style.left = newLeft + 'px'
// 点的切换
// 移除所有导航点的active类
dots.forEach(function (dot) {
dot.classList.remove('active')
})
// 当前索引的导航点 增加 active 类
dots[index].classList.add('active')
})优化-过渡效果
当按下时移除过度样式,抬起时添加样式即可。
container.addEventListener('touchstart', function (e) {
// 移除过度效果
wrapper.style.transition = 'none'
})
container.addEventListener('touchend', function (e) {
// 增加过度
wrapper.style.transition = 'all .5s'
}元素初始化设置
为元素设置初始高度宽度以及动态创建导航点的个数
// 初始化函数
function init() {
// 容器设置 高度
window.onload = function () {
// 获取第一个图片的高度
const h = slides[0].offsetHeight
container.style.height = h + 'px'
}
// 包裹元素的宽度
wrapper.style.width = slides.length * 100 + '%'
// 设置子元素的宽度
slides.forEach((item) => {
item.style.width = 100 / slides.length + '%'
})
// 根据图片数量动态创建导航点的个数
for (var i = 0; i < slides.length; i++) {
const span = document.createElement('span')
if (i == 0) {
span.className = 'active'
}
pagination.appendChild(span)
}
dots = container.querySelectorAll('.swiper-pagination span')
}
init()无缝滚动
无缝滚动采用的方案是新插入一组一模一样的图片,当向左滑动(第一张)时迅速切换到第二组的第一张。
// 无缝滚动
wrapper.innerHTML += wrapper.innerHTML
const slidesNew = container.querySelectorAll('.swiper-slide')
container.addEventListener('touchstart', function (e) {
// 移除过度效果
wrapper.style.transition = 'none'
// 获取按下时的时间点
this.touchStartTime = Date.now()
// 判断索引下标
if (index == 0) {
index = slides.length
const newLeft = -index * container.offsetWidth
// 设置left的样式
wrapper.style.left = newLeft + 'px'
}
// 右侧边界
if (index == slidesNew.length - 1) {
index = slides.length - 1
const newLeft = -index * container.offsetWidth
// 设置left的样式
wrapper.style.left = newLeft + 'px'
}
// 获取触摸开始时的触点位置
this.x = e.touches[0].clientX
// 获取包裹元素的水平偏移量
this.left = wrapper.offsetLeft
})自动播放
// 自动播放
function autoRun() {
// 防止定时器重复
clearInterval(timer)
// 启动定时器
timer = setInterval(function () {
// 索引自增 切换幻灯片
index++
// 增加过度
wrapper.style.transition = 'all .5s'
const newLeft = -index * container.offsetWidth
// 设置left的样式
wrapper.style.left = newLeft + 'px'
// 点的切换
// 移除所有导航点的active类
dots.forEach(function (dot) {
dot.classList.remove('active')
})
// 当前索引的导航点 增加 active 类
dots[index % slides.length].classList.add('active')
}, 1000)
}
autoRun()
// 动画过渡完毕时间
wrapper.addEventListener('transitionend', (e) => {
// 是不是最后一张
if (index === slidesNew.length - 1) {
// 移除过渡
wrapper.style.transition = 'none'
index = slides.length - 1
const newLeft = -index * container.offsetWidth
// 设置left的样式
wrapper.style.left = newLeft + 'px'
}
})封装及优化后的JavaScript代码
import '../style/index.less'
const app = document.querySelector('#app')
const container = document.querySelector('#swiper-container')
const wrapper = container.querySelector('.swiper-wrapper')
// 获取所有图片
const slides = container.querySelectorAll('.swiper-slide')
// 当前显示的图片的下标
var index = 0
// 获取所有小圆点
let dots = null
// 获取小圆点的容器
const pagination = container.querySelector('.swiper-pagination')
// 定时器
let timer = null
// 无缝滚动
wrapper.innerHTML += wrapper.innerHTML
const slidesNew = container.querySelectorAll('.swiper-slide')
// 标识变量
let isHori = true
let isFirst = true
// 触摸开始事件
container.addEventListener('touchstart', function (e) {
wrapper.style.transition = 'none'
// 获取按下时的时间点
this.touchStartTime = Date.now()
// 判断索引下标
if (index == 0) {
index = slides.length
}
// 右侧边界
if (index == slidesNew.length - 1) {
index = slides.length - 1
}
container.switchSlide(index, false)
// 获取触摸开始时的触点位置
this.x = e.touches[0].clientX
this.y = e.touches[0].clientY
// 获取包裹元素的水平偏移量
this.left = wrapper.offsetLeft
// 停止定时器
clearInterval(timer)
})
// 触摸滑动时事件
container.addEventListener('touchmove', function (e) {
this._x = e.touches[0].clientX
this._y = e.touches[0].clientY
// 垂直方向上的偏移
const disY = Math.abs(this._y - this.y)
// 水平方向上的偏移
const disX = Math.abs(this._x - this.x)
if (isFirst) {
// 标识变量赋值为 假
isFirst = false
if (disY > disX) {
isHori = false
}
if (disY < disX) {
isHori = true
}
}
if (isHori) {
e.preventDefault()
} else {
return
}
// 计算新的left值
const newLeft = this._x - this.x + this.left
// 设置left的值
wrapper.style.left = newLeft + 'px'
})
// 触摸结束事件
container.addEventListener('touchend', function (e) {
isFirst = true
if (!isHori) return
// 获取触点结束时触点位置
this._x = e.changedTouches[0].clientX
// 判断距离
const disX = Math.abs(this._x - this.x)
// 判断时间
this.touchEndTime = Date.now()
if (
disX > container.offsetWidth / 2 ||
this.touchEndTime - this.touchStartTime <= 300
) {
// 向左滑动
if (this._x < this.x) {
index++
}
// 向右滑动
if (this._x > this.x) {
index--
}
}
// 检测是否越界
if (index < 0) {
index = 0
}
if (index > slidesNew.length - 1) {
index = slidesNew.length - 1
}
this.switchSlide(index)
// 启动定时器
this.autoRun()
})
// 动画过渡完毕时间
wrapper.addEventListener('transitionend', (e) => {
// 是不是最后一张
if (index === slidesNew.length - 1) {
index = slides.length - 1
container.switchSlide(index, false)
}
})
// 初始化函数
container.init = function () {
// 容器设置 高度
window.onload = function () {
// 获取第一个图片的高度
const h = slidesNew[0].offsetHeight
container.style.height = h + 'px'
}
// 包裹元素的宽度
wrapper.style.width = slidesNew.length * 100 + '%'
// 设置子元素的宽度
slidesNew.forEach((item) => {
item.style.width = 100 / slidesNew.length + '%'
})
// 根据图片数量动态创建导航点的个数
for (var i = 0; i < slides.length; i++) {
const span = document.createElement('span')
if (i == 0) {
span.className = 'active'
}
pagination.appendChild(span)
}
dots = container.querySelectorAll('.swiper-pagination span')
}
container.init()
// 自动播放
container.autoRun = function () {
// 防止定时器重复
clearInterval(timer)
// 启动定时器
timer = setInterval(function () {
// 索引自增 切换幻灯片
index++
container.switchSlide(index)
}, 1000)
}
container.autoRun()
// 切换幻灯片
container.switchSlide = function (i, isTransition) {
if (isTransition === undefined) {
isTransition = true
}
if (isTransition) {
// 增加过度
wrapper.style.transition = 'all .5s'
} else {
// 增加过度
wrapper.style.transition = 'none'
}
/**
* index => left
* 0 => 0
* 1 => index * -375
*/
// 计算新的left的值
const newLeft = -i * container.offsetWidth
// 设置left的样式
wrapper.style.left = newLeft + 'px'
// 点的切换
// 移除所有导航点的active类
dots.forEach(function (dot) {
dot.classList.remove('active')
})
// 当前索引的导航点 增加 active 类
dots[i % slides.length].classList.add('active')
index = i
} 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 小康博客!
评论
TwikooDisqusjs












