900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 原生JS实现PC端无缝滚动轮播图 匀速轮播图 匀速动画

原生JS实现PC端无缝滚动轮播图 匀速轮播图 匀速动画

时间:2018-08-05 21:49:56

相关推荐

原生JS实现PC端无缝滚动轮播图 匀速轮播图 匀速动画

offset家族的了解

1.offsetHeight:元素的offsetHeight是一种元素CSS高度的衡量标准,包括元素的边框、内边距和元素的水平滚动条(如果存在且渲染的话),不包含:before或:after等伪类元素的高度。检测盒子的高度,包括padding和border;不包括margin

2.offsetWidth:是一个只读属性,返回一个元素的布局宽度。一个典型的(译者注:各浏览器的offsetWidth可能有所不同)offsetWidth是测量包含元素的边框(border)、水平线上的内边距(padding)、竖直方向滚动条(scrollbar)(如果存在的话)、以及CSS设置的宽度(width)的值。检测盒子的宽度,包括padding和border;不包括margin

3.offsetParent:是一个只读属性,返回一个指向最近的(closest,指包含层级上的最近)包含该元素的定位元素。如果没有定位的元素,则 offsetParent 为最近的 table, table cell 或根元素.

4.offsetLeft:是一个只读属性,返回当前元素左上角相对于 HTMLElement.offsetParent 节点的左边界偏移的像素值。返回距离定位盒子左侧的边界,没有定位父系盒子没有则返回,距离左侧(body)的位置

5.offsetTop:为只读属性,它返回当前元素相对于其 offsetParent 元素的顶部的距离。

实现无缝滚动匀速轮播图函数的封装

我们移动轮播图,其实就是实现控制装每个轮播图(一般情况是li)的最外层盒子的移动(一般情况是ul)

实现盒子匀速移动到指定位置

<style>.box1{position: relative;}.box2{position: absolute;width: 100px;height: 100px;background: red;margin-top: 20px;}</style><div class="box1"><button class="btn1">移动到400的位置</button><button class="btn2">移动到800的位置</button><div class="box2"></div></div>

利用定时器和offsetLeft来实现匀速运动

使用定时器每段时间走一定的步数(step:10)当盒子向右走step为正,当盒子向左走step为负数(目标位置和当前盒子位置比较)开启定时器当目标位置和当前位置的距离相等或则小于要走的步数,清除定时器,直接跳到目标位置每次开启定时器之前先清除定时器,防止多次调用定时器

function animate(el,target){// 每次调用函数要先清除定时器,防止多次点击时会开启多个定时器,影响匀速运动clearInterval(el.timer)// 每次让盒子走十步// var step = 10// 因为要考虑向右走还是向左走,所以step要根据当前位置和目标位置取正负var current = el.offsetLeftvar step = target-current>0?10:-10;el.timer = setInterval(function(){// 每次重新获取盒子当前位置current = el.offsetLeft// 每次走十步el.style.left = current + step + 'px'// 当前位置和目标位置的距离小于要走的步数距离.直接让其走到目标位置// 防止超过目标位置,接着清除定时器if(Math.abs(target-current)<Math.abs(step)){el.style.left = target + 'px'clearInterval(el.timer)}}, 10)}

style.left和offsetLeft

style.left可读可写,offsetLeft只读,我们为什么不使用style.left,而要使用offsetLeft来获取盒子的当前位置?

style.left只能获取行内样式的定位

<div class="box2" style="left: 10px"></div>

offsetLeft可以返回没有定位盒子的距离左侧的位置,style.left没有定位盒子,返回的是""style.left返回的是字符串,offsetLeft返回的是number

实现无缝滚动轮播图

注:开发过程中可以将.slider的overflow:hidden的css样式去掉

<div class="all" id='box'><div class="slider"><ul><li><img src="img/banner1.jpg" alt="slider" width="590px" height="470px" /></li><li><img src="img/banner2.jpg" alt="slider" width="590px" height="470px" /></li><li><img src="img/banner3.jpg" alt="slider" width="590px" height="470px" /></li><li><img src="img/banner4.jpg" alt="slider" width="590px" height="470px" /></li><li><img src="img/banner5.jpg" alt="slider" width="590px" height="470px" /></li><li><img src="img/banner6.jpg" alt="slider" width="590px" height="470px" /></li></ul><ol></ol></div><div id="arr"><span id="left">&lt;</span><span id="right">&gt;</span></div></div>

<style type="text/css">* {padding: 0;margin: 0;list-style: none;border: 0;}.all {width: 590px;height: 470px;padding: 7px;border: 1px solid #ccc;margin: 100px auto;position: relative;}.slider {width: 590px;height: 470px;overflow: hidden;position: relative;}.slider li {width: 590px;height: 470px;overflow: hidden;float: left;}.slider ul {position: absolute;left: 0;top: 0px;width: 700%;}.all ol {position: absolute;right: 10px;bottom: 10px;line-height: 20px;text-align: center;}.all ol li {float: left;width: 20px;height: 20px;background: #fff;border: 1px solid #ccc;margin-left: 10px;cursor: pointer;}.all ol li.current {background: yellow;}#arr {display: none;z-index: 1000;}#arr span {width: 40px;height: 40px;position: absolute;left: 5px;top: 50%;margin-top: -20px;background: #000;cursor: pointer;line-height: 40px;text-align: center;font-weight: bold;font-family: '黑体';font-size: 30px;color: #fff;opacity: 0.3;border: 1px solid #fff;}#arr #right {right: 5px;left: auto;}</style>

JS代码的实现
将上面的匀速动画函数复制并改造一下

Object.prototype.myAnimate = function(target){if(this.nodeType!==1){console.log('不是元素节点')return;}clearInterval(this.timer)var current = this.offsetLeftvar step = target-current>0?10:-10;this.timer = setInterval(()=>{current = this.offsetLeftthis.style.left = current + step + 'px'if(Math.abs(target-current)<Math.abs(step)){this.style.left = target + 'px'clearInterval(this.timer)}}, 10)}

我们使用JS高级的原型来封装一个匀速运动的方法,箭头函数主要是不改变this的指向,nodeType来判断是不是dom节点

2. 获取和设置后面需要用到的元素

3. 添加按钮:根据轮播图,创建ol的li按钮

4. 复制第一张图片将其添加到最后,来实现无缝滚动(当前第一张和最后一张的链接)

5. 在添加个定时器实现自动播放

6. 点击ol的按钮轮播到该索引值对应的时间切换图片

7. 测试看看是否会不会出bug

8. 控制左右移动

说明:代码的步骤和上面的步骤是一一对应的,我这里将解释都写在代码里面了

// 1. 将上面的匀速动画函数复制并改造一下Object.prototype.myAnimate = function(target){if(this.nodeType!==1){console.log('不是元素节点')return;}clearInterval(this.timer)var current = this.offsetLeftvar step = target-current>0?10:-10;this.timer = setInterval(()=>{current = this.offsetLeftthis.style.left = current + step + 'px'if(Math.abs(target-current)<Math.abs(step)){this.style.left = target + 'px'clearInterval(this.timer)}}, 10)}// 2.获取和设置后面需要用到的元素var box = document.querySelector('#box')//获取轮播图和按钮的容器var ul = document.querySelector('.slider>ul')//轮播图容器var ol = document.querySelector('.slider>ol')//按钮容器var ulLi = ul.children//获取每个轮播图var sIndex = 0//控制播放的轮播图的索引值var liIndex = 0//控制li的当前样式var timer = null//自动轮播时的定时器var arr = document.querySelector('#arr')var arrLeft = document.querySelector('#left')var arrRight = document.querySelector('#right')var imgWidth = ulLi[0].offsetWidth//获取图片的宽度,实现轮播// 3.添加按钮:根据轮播图,创建ol的li按钮for(var i=0;i<ulLi.length;i++){var olLi = document.createElement('li')olLi.innerHTML = i+1if(i==0){olLi.classList.add('current')}ol.appendChild(olLi)}// 4.复制第一张图片将其添加到最后,来实现无缝滚动(当前第一张和最后一张的链接)ul.appendChild(ulLi[0].cloneNode(true))// 5.在添加个定时器实现自动播放var olList = ol.children //获取ol的li按钮function autoplay(){// 5.1自动播放主要控制sIndex实现自动轮播// 5.2通过liIndex控制ol选中的样式// 5.3我们要控制sIndex和liIndex,限制在一定的范围// 5.4当轮播图处于最后一张(sIndex=5),要移动到第一张(sIndex=0),正常移动到复制的第一张(sIndex=6),但是当复制的第一张(sIndex=6)要移动到第二张(sIndex=1)时,先瞬间定位到第一张(sIndex=0),在移动到第二张(sIndex=1)// 5.5此刻在控制liIndex,当超出当前索引值,将回到第一个按钮if(sIndex>ulLi.length-1){ul.style.left = '0px'sIndex = 1}if(liIndex>olList.length-1){liIndex = 0}// 8.3当点击左按钮时,此时如果轮播图处于第一张(sIndex=0),我们瞬间要移动到复制的第一张(sIndex=ulLi.length-1=6),在滚动到最后一张(sIndex=ulLi.length-2=5)if(sIndex<0){ul.style.left = -(ulLi.length-1)*imgWidth + 'px'sIndex = ulLi.length-2}// 8.4此刻在控制liIndex按钮,当索引值小于0时,回到最后一个if(liIndex<0){liIndex = olList.length - 1}document.querySelector('.current').classList.remove('current') olList[liIndex].classList.add('current')ul.myAnimate(-sIndex*imgWidth) }timer = setInterval(function(){this.sIndex ++this.liIndex ++autoplay()},1000)// 6.点击ol的按钮轮播到该索引值对应的时间切换图片for(var i=0;i<olList.length;i++){olList[i].setAttribute('index', i)//给每个li设置index,根据index和图片宽度来确定目标位置olList[i].onclick = function(){document.querySelector('.current').classList.remove('current')this.classList.add('current')//点击添加当前选中样式高亮的类liIndex = sIndex = this.getAttribute('index')//因为我们自动播放,所以要始终控制当前ol的li高亮和sIndex全局保持一致,不控制的话,点击完后,sIndex和liIndex没有根据点击选中的发生改变ul.myAnimate(-this.getAttribute('index')*imgWidth)}}// 7.测试看看是否正常播放// 8.控制左右移动// 8.1 经过屏幕,停止自动轮播,左右切换// 8.2 离开屏幕。继续自动轮播,隐藏左右切换// 8.5 点击左右按钮调用autoplay播放box.onmouseenter = function(){clearInterval(timer)arr.style.display = 'block'}box.onmouseleave = function(){timer = setInterval(function(){sIndex++liIndex++autoplay()},2000)arr.style.display = 'none'}arrRight.onclick = function(){sIndex++liIndex++autoplay()}arrLeft.onclick = function(){sIndex--liIndex--autoplay()}

思路

获取:获取我们所需要的元素

反馈:我们要实现的是左右切换无缝轮播,自动播放无缝轮播和点击按钮滑动轮播,所以我们要时刻控制轮播图的索引值(sIndex)保持一致,并对其进行限制,通过控制sIndex结合图片宽度(imgWidth)来控制目标位置来实现无缝滚动

处理:因为是无缝滚动,所以我们要将第一张图片复制并添加到最后,封装好通过sIndex来控制的函数,来控制目标位置实现滚动。

点击ol的li实现点击按钮滑动播放:根据点击索引值来实现播放自动播放:每次滚动一张,添加定时器timer来自动播放,此刻的时间(这里是1000)需要比我们的匀速播放的时间(这里是10)要大左右切换,每点击一次,改变sIndex的值进行播放最后控制ol的里高亮样式

百尺竿头,更进一步

上面是左右轮播图,如果是垂直轮播图,或则需要宽高匀速变化,我们需要进行一下变化
获取属性的兼容处理

function getStyle(ele,attr){if(window.getComputedStyle){return window.getComputedStyle(ele,null)[attr];}return ele.currentStyle[attr];}

匀速动画 我们需要使用对象来调用它(传入的参数为{}),在增加一个回调函数记住一点,我们使用开闭原则来保证所有动画的完成,否则可能只完成一半

function animate(el,json,fn){clearInterval(el.timer)el.timer = setInterval(function(){var bool = true //当所有的动画完成,我们才可以清除定时器,所以要使用开闭原则for(var attr in json){var current = parseInt(getStyle(el,attr))var step = json[attr]-current>0?10:-10;el.style[attr] = current + step + 'px'if(Math.abs(json[attr]-current)>Math.abs(step)){bool = false //此时所有的动画都未完成return}el.style[attr] = json[attr] + 'px'}if(bool){//所有动画完成我们才能清除定时器clearInterval(el.timer)fn && fn()}}, 10)}

测试

btn1.onclick = function(){animate(box,{width:'400',height:'405'},function(){console.log('所有动画完成的回调函数')})}

如果想要使用背景透明度和层级等…此时我们只需要判断attr属性就可以

function animate(el,json,fn){clearInterval(el.timer)el.timer = setInterval(function(){var bool = truefor(var attr in json){if(attr==='opacity'){var current = parseInt(getStyle(el,attr)) * 100var step = json[attr]*100-current>0?10:-10;el.style[attr] = (current + step)/100if(Math.abs(json[attr]*100-current)>Math.abs(step)){bool = falsereturn}el.style[attr] = json[attr]}else{var current = parseInt(getStyle(el,attr))var step = json[attr]-current>0?10:-10;el.style[attr] = current + step + 'px'if(Math.abs(json[attr]-current)>Math.abs(step)){bool = falsereturn}el.style[attr] = json[attr] + 'px'}}if(bool){clearInterval(el.timer)fn && fn()}}, 10)}

总结

开发中,一般使用swiper,或则jquery已经封装好的动画上面是匀速动画,我们需要缓动动画只需要改变步数step即可

var step = (target - current)/10step = step>0?Math.ceil(step):Math.floor(step)

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