900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 原生JS实现无缝轮播

原生JS实现无缝轮播

时间:2018-12-28 05:23:08

相关推荐

原生JS实现无缝轮播

什么叫无缝轮播

无缝轮播是网页中比较常见的一种轮播方式,很多网站首页都应用了无缝轮播,这种效果使页面看起来更顺滑。

先来看一下我实现的效果图:

无缝轮播的实现

下面用示意图清楚的展现了无缝轮播的原理:

一共有3张图片轮播,但是为什么有5张图片呢?这是因为要想实现无缝轮播的效果,就要用“障眼法”。

每当图片滚动到最后一张或者第一张时,都会自动回到第一张或最后一张,加入这两张图片有一个过渡的效果。

原理分析

好了,在介绍了无缝轮播之后,小伙伴们是不是跃跃欲试了呢,别着急,在正式写代码之前让我们先把逻辑理清楚。

假设当前正在播放的图片是1,令currentIndex = 1,当前left = 实际运动过程中距离左边的长度,目标left = 要切换的图片距离左边的长度,且这两个均为负数。

如果当前图片移动方向是向左,当目标left < 当前left时,假设是从0移动到2:

//目标left,index是要切换的图片的索引,imgWidth是图片宽度var newLeft = index * imgWidth;//计算需要移动的总距离var distance = newLeft - marginLeft;

目标left > 当前left时,假设是从2移动到0:

//3张图片总宽var totalWidth = 3 * igmWidth;distance = -(totalWidth - Math.abs(newLeft - marginLeft));

接下来分析图片向右移动的情况

目标left > 当前left时,这时候移动的就是正数了

distance = newLeft - marginLeft;

目标left < 当前left

distance = totalWidth - Math.abs(newLeft - marginLeft);

设置动画效果

好的,既然逻辑清楚了,接下来就是愉快的写代码环节。

/*** 切换到某一个图片的索引* @param {*} index 要切换到目标的图片的索引* @param {*} direction 图片移动的方向 "left" "right"*/function switchTo(index, direction) {if (index == config.currentIndex) {return;}if (!direction) {direction = "left";}//最终的marginLeftvar newLeft = (-index - 1) * config.imgWidth;animateSwitch();//重新设置当前索引config.currentIndex = index;//设置小圆点的选中状态setDotsActiveStatus();/*** 逐步改变marginLeft*/function animateSwitch() {//先停止之前的动画stopAnimate();//1、计算运动的次数var number = Math.ceil(config.timer.total / config.timer.duration);//当前的运动次数var currentNum = 0;//2、计算需要移动总距离var distance;//获取当前的left值var marginLeft = parseFloat(getComputedStyle(config.doms.divImgs).marginLeft);var totalWidth = config.imgsNum * config.imgWidth;if (direction == "left") {if (newLeft < marginLeft) {distance = newLeft - marginLeft;} else {distance = -(totalWidth - Math.abs(newLeft - marginLeft));}} else {if (newLeft > marginLeft) {distance = newLeft - marginLeft;} else {distance = totalWidth - Math.abs(newLeft - marginLeft);}}//3、计算每次运动的距离var everyDistance = distance / number;//将函数注册为config.timer.duration秒后调用,之后每隔config.timer.duration之后重复调用config.timer.id = setInterval(function () {//改变div的marginLeftmarginLeft += everyDistance;if (direction == "left" && Math.abs(marginLeft) > totalWidth) {marginLeft += totalWidth;} else if (direction == "right" && Math.abs(marginLeft) < config.imgWidth) {marginLeft -= totalWidth;}config.doms.divImgs.style.marginLeft = marginLeft + "px";currentNum++;if (currentNum == number) {stopAnimate();}}, config.timer.duration)function stopAnimate() {clearInterval(config.timer.id);config.timer.id = null;}}}

这里我定义了一个函数去处理切换图片的逻辑,里面的animateSwitch函数就是处理切换动画的,注意首先要停止当前动画,要不然一直点击的时候,就会一直执行这个函数,导致速度越来越快。

之后就是我们前面分析过的逻辑,计算出移动的总距离,再算出每次运动的距离,通过这个距离再调用setInterval计时器,需要判断的是当图片移动到最后一张时怎么重新回到第一张,这里我们把marginLeft的绝对值减去总宽度。

当到达marginLeft = totalWidth这个临界值时,说明图片到了最后一张或者第一张,这个时候判断一下图片的运动方向,如果图片向左运动,下一次刷新假如到了下图位置:

这个时候令marginLeft = marfinLeft + totalWidth就会运动到如下图位置,当然这个在浏览器中刷新是非常快的,人眼是感觉不到已经变化的了

图片向右运动同理,只需要将marginLeft = marfinLeft - totalWidth即可

最后要取消动画的时候,只需要把计时器清除,并将id设为null。

以上就是无缝轮播的核心代码以及逻辑分析,仅供参考,各位小伙伴们如果看懂了一定要自己动手练习,我会把整个js代码和整个项目都放在末尾,有需要的可以看一下,也可以私信我发给你。前端知识多而乱,只有掌握好基础后期才能游刃有余。

附JS代码

//轮播配置对象var config = {imgWidth: 640, //图片宽度dotsWidth: 8, //圆点宽度doms: {//dom对象divImgs: document.querySelector('.img'),divDots: document.querySelector('.dots'),divArrow: document.querySelector('.arrow'),divLeft: document.querySelector('.left'),divRight: document.querySelector('.right'),},currentIndex: 0, //当前显示的图片索引 0 ~ imgsNum-1timer: {//运动计数器配置duration: 16, //运动间隔的时间total: 500, //运动的总时间,单位毫秒id: null //计时器的id},autoTimer: null //自动移动的计时器};//图片数量config.imgsNum = config.doms.divImgs.children.length;/*** 初始化函数*/function init() {//初始化元素尺寸initSize();//初始化元素initElements();//初始化显示图片的位置initImgPosition();//设置小圆点的选中状态setDotsActiveStatus();}init();/*** 初始化元素尺寸*/function initSize() {//包裹圆点的尺寸,+6是margin相加的值config.doms.divDots.style.width = (config.dotsWidth + 6) * config.imgsNum + "px";//轮播图整体尺寸config.doms.divImgs.style.width = config.imgWidth * (config.imgsNum + 2) + "px";}/*** 初始化元素*/function initElements() {//创建小圆点for (var i = 0; i < config.imgsNum; i++) {var span = document.createElement('span');config.doms.divDots.appendChild(span);}//复制图片,实现无缝轮播var children = config.doms.divImgs.children;//第一张图片var first = children[0];//最后一张图片var last = children[children.length - 1];var newImg = first.cloneNode(true); //深度克隆config.doms.divImgs.appendChild(newImg);newImg = last.cloneNode(true); //深度克隆config.doms.divImgs.insertBefore(newImg, first);}/*** 初始化显示图片的位置*/function initImgPosition() {//设置的currentIndex为几就显示第几张图片var left = (-config.currentIndex - 1) * config.imgWidth;config.doms.divImgs.style.marginLeft = left + "px";}/*** 设置小圆点的选中状态*/function setDotsActiveStatus() {//小圆点外边框var children = config.doms.divDots.children;for (var i = 0; i < children.length; i++) {var dot = children[i];if (i == config.currentIndex) {dot.className = "active";} else {dot.className = "";}}}/*** 切换到某一个图片的索引* @param {*} index 要切换到目标的图片的索引* @param {*} direction 图片移动的方向 "left" "right"*/function switchTo(index, direction) {if (index == config.currentIndex) {return;}if (!direction) {direction = "left";}//最终的marginLeftvar newLeft = (-index - 1) * config.imgWidth;animateSwitch();//重新设置当前索引config.currentIndex = index;setDotsActiveStatus();/*** 逐步改变marginLeft*/function animateSwitch() {//先停止之前的动画stopAnimate();//1、计算运动的次数var number = Math.ceil(config.timer.total / config.timer.duration);//当前的运动次数var currentNum = 0;//2、计算需要移动总距离var distance;//当前的left值var marginLeft = parseFloat(getComputedStyle(config.doms.divImgs).marginLeft);var totalWidth = config.imgsNum * config.imgWidth;if (direction == "left") {if (newLeft < marginLeft) {distance = newLeft - marginLeft;} else {distance = -(totalWidth - Math.abs(newLeft - marginLeft));}} else {if (newLeft > marginLeft) {distance = newLeft - marginLeft;} else {distance = totalWidth - Math.abs(newLeft - marginLeft);}}//3、计算每次运动的距离var everyDistance = distance / number;//将函数注册为config.timer.duration秒后调用,之后每隔config.timer.duration之后重复调用config.timer.id = setInterval(function () {//改变div的marginLeftmarginLeft += everyDistance;if (direction == "left" && Math.abs(marginLeft) > totalWidth) {marginLeft += totalWidth;} else if (direction == "right" && Math.abs(marginLeft) < config.imgWidth) {marginLeft -= totalWidth;}config.doms.divImgs.style.marginLeft = marginLeft + "px";currentNum++;if (currentNum == number) {stopAnimate();}}, config.timer.duration)function stopAnimate() {clearInterval(config.timer.id);config.timer.id = null;}}}/*** 点击左右按钮和小圆点切换图片*/function changeImg() {//给按钮注册点击事件config.doms.divArrow.onclick = function (e) {if (e.target.classList.contains("left")) {var index = config.currentIndex - 1;if (index < 0) {index = config.imgsNum - 1;}switchTo(index, "right");} else {var index = (config.currentIndex + 1) % config.imgsNum;switchTo(index, "left");}}//给小圆点注册点击事件config.doms.divDots.onclick = function (e) {if (e.target.tagName == "SPAN") {var index = Array.from(this.children).indexOf(e.target);switchTo(index, index > config.currentIndex ? "left" : "right");}}}//点击左右按钮切换图片changeImg();/*** 自动轮播*/config.autoTimer = setInterval(function() {var index = (config.currentIndex + 1) % config.imgsNum;switchTo(index, "left");}, 3000);

整个项目zip

百度网盘链接:/s/1vQB8t_dI1zZeeXa-TA9rzw

提取码:6ie9

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。