链式动画
就是动画执行完接另一个动画 , 不断的进行链接
封装进阶 ( 通过传入回调函数完成链式运动 )
// 0.缓冲运动的封装 // element表示元素,targetObj表示目标对象,callbackFn是回调函数,用来解决异步变成同步的 function bufferAnimation(element, targetObj, callbackFn) { // 1.判断是否有传入元素,没有就直接报错 if (!element) { throw new Errow('元素不能少') } // 2.给元素设置一个定时器,以便后续动画的操作 element.timer = setInterval(() => { // 3.设置默认所有的动画都是没问题的 var flag = true // 4.遍历目标对象 for (let key in targetObj) { // 5.取出当前样式值 let current = parseFloat(getStyle(element)[key]) // 6.取出目标值 let target = targetObj[key] // 7.如果是宽高的变化 if (key == 'width' || key == 'height' || key == 'top' || key == 'left') { // 8.那步长是负数就向下取整,正数就向上取整 let step = target - current > 0 ? Math.ceil((target - current) / 10) : Math.floor((target - current) / 10) current += step // 9.设置样式 element.style[key] = current + 'px' } // 10.如果是透明度的变化 if (key == 'opacity') { // 11.它的步长也还是负树向下取整,正数向上取整,但是因为透明度最小是0,最大是1,所以要先放大,设置的时候再缩小 let step = target - current > 0 ? Math.ceil((target - current) * 1000 / 10) : Math.floor((target - current) * 1000 / 10) current += step / 1000 // 12.设置样式 element.style[key] = current } // 13.如果是层高的变化,那它的样式就直接等于目标值 if (key == 'zIndex') { element.style[key] = target } // 14.如果当前值不等于目标值,就是没有完成,返回false,定时器不会清除,效果也不会呈现 if (current != target) { flag = false } } // 15.如果全部走完了,就清除定时器,显示效果 if (flag) { clearInterval(element.timer) // 16.判断后面传入的参数是否为函数,是就调用 if (typeof callbackFn == 'function') { callbackFn() } } }, 20) }
实例 ( 先变化div的宽高再改变它的位置 )
<button>变变变</button> <div></div> <script src="./js/运动封装.js"></script> <script> // 获取div和按钮 var div = document.querySelector('div') var btn = document.querySelector('button') // 给按钮设置点击事件 btn.onclick = function () { // 先让宽高变化,再变化位置 // 调用缓冲动画(需求是有两个异步操作,在不知道那个异步先执行完的时候可以通过回调函数来解决异步问题,让异步变同步) buffer(div, { width: 666, height: 300 }, () => { // 变化位置 buffer(div, { top: 200 }, () => { // 变化位置 buffer(div, { left: 200 }) }) }) } </script>
轮播图
核心
-
滚动切换 ( 更改的是大盒子的位置 )
-
透明度切换 ( 更改的是图片的透明度 )
-
图片切换 ( 直接变化图片的位置 )
滚动切换
-
大盒子里面容纳多个图片 ,
-
图片的大小和显示盒子的大小一致 ,
-
大盒子的大小超出了显示盒子 ( 溢出隐藏 )
-
根据切换的下标来控制大盒子的位置
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; list-style: none; } .showBox, li, img { width: 400px; height: 250px; } .showBox { margin: 200px auto; overflow: hidden; } ul { width: 800%; position: relative; } li { float: left; } </style> </head> <body> <div class="showBox"> <ul> <li><img src="./images/slidepic1.jpg" alt=""></li> <li><img src="./images/slidepic2.jpg" alt=""></li> <li><img src="./images/slidepic3.jpg" alt=""></li> <li><img src="./images/slidepic4.jpg" alt=""></li> <li><img src="./images/slidepic5.jpg" alt=""></li> <li><img src="./images/slidepic6.jpg" alt=""></li> <li><img src="./images/slidepic7.jpg" alt=""></li> <li><img src="./images/slidepic8.jpg" alt=""></li> </ul> </div> <script src="./js/运动封装.js"></script> <script> // 滚动自动轮播 // 1.获取显示的盒子和ul var showBox = document.querySelector('.showBox') var ul = document.querySelector('ul') // 2.2获取图片的宽度 var showBoxWidth = parseFloat(getStyle(showBox).width) // 2.封装一个自动轮播的方法 function autoPlay() { // 2.1 根据下标来切换,设置默认下标为0 var index = 0 // 2.3 设置定时器,2秒切换下一张 var timer = setInterval(() => { index++ // 2.4 如果下标等于图片的长度了就切换成第一张图片 if (index == ul.children.length) { index = 0 } // 2.5 调用动画根据(下标*图片宽度*-1)来实现轮播 buffer(ul, { left: showBoxWidth * index * -1 }) }, 2000) } // 3.调用自动轮播的方法 autoPlay() </script> </body> </html>
透明度切换
-
所有的图叠在一起
-
将前面图片的透明度设置为0,当前图片设置为1
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { padding: 0; margin: 0; list-style: none; } .showBox, li, img { width: 400px; height: 250px; } .showBox { margin: 200px auto; overflow: hidden; } .wrap { width: 800%; } li { float: left; opacity: 0; position: absolute; } ul>li:nth-child(1) { opacity: 1; } </style> </head> <body> <div class="showBox"> <ul class="wrap"> <li><img src="./images/slidepic1.jpg" alt=""></li> <li><img src="./images/slidepic2.jpg" alt=""></li> <li><img src="./images/slidepic3.jpg" alt=""></li> <li><img src="./images/slidepic4.jpg" alt=""></li> <li><img src="./images/slidepic5.jpg" alt=""></li> <li><img src="./images/slidepic6.jpg" alt=""></li> <li><img src="./images/slidepic7.jpg" alt=""></li> <li><img src="./images/slidepic8.jpg" alt=""></li> </ul> </div> <script src="./js/运动封装.js"></script> <script> // 获取ul var wrap = document.querySelector('.wrap') // 封装一个切换图片及设置透明度的方法 function move() { // 设置默认的下标为0 var index = 0 // 切换图片的定时器 var timer = setInterval(() => { // 改透明度,先将切换前的全部设置为0 buffer(wrap.children[index], { opacity: 0 }, () => { // 进行图片切换 index++ // 到了最后就切换到第一个 if (index == wrap.children.length) { index = 0 } // 再将自己的透明度改为1 buffer(wrap.children[index], { opacity: 1 }) }) }, 2000) } // 调用方法 move() </script> </body> </html>
图片切换
- 根据图片的编号来切换对应的图片
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { padding: 0; margin: 0; list-style: none; } .showBox, img { width: 400px; height: 250px; } .showBox { margin: 200px auto; } </style> </head> <body> <div class="showBox"> <img src="./images/slidepic1.jpg" alt=""> </div> <script src="./js/运动封装.js"></script> <script> // 获取图片 var img = document.querySelector('.showBox img') // 封装一个移动的方法 function move() { // 根据图片编号来切换和生成图片,默认为1 var i = 1 // 设置切换图片的定时器 var timer = setInterval(() => { i++ // 如果编号超出图片的编号就切换成第一张 if (i == 7) ( i = 1 ) // 设置图片地址 img.src = `./images/slidepic${i}.jpg` }, 2000) } // 调用自动移动的方法 move() </script> </body>
无缝轮播 ( 滚动轮播的进阶 )
-
拷贝第一张到最后
-
判断是否到达最后一张,到了就设置到第一张的位置
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } .showBox, li { width: 400px; height: 250px; } li>img { width: 100%; } .showBox { margin: 200px auto; /* 溢出隐藏 */ overflow: hidden; } ul { width: 800%; position: relative; } ul>li { list-style: none; float: left; } </style> </head> <body> <div class="showBox"> <ul class="wrap"> <li><img src="./images/slidepic1.jpg" alt=""></li> <li><img src="./images/slidepic2.jpg" alt=""></li> <li><img src="./images/slidepic3.jpg" alt=""></li> <li><img src="./images/slidepic4.jpg" alt=""></li> <li><img src="./images/slidepic5.jpg" alt=""></li> <li><img src="./images/slidepic6.jpg" alt=""></li> <li><img src="./images/slidepic7.jpg" alt=""></li> </ul> </div> <script src="./move.js"></script> <script> //获取显示盒子 var showBox = document.querySelector('.showBox') //获取显示盒子的宽度 var showWidth = parseFloat(getStyle(showBox).width) //获取ul(需要切换位置的容器) var wrap = document.querySelector('.wrap') //拷贝第一张图加到最后 //克隆第一个li var firstLi = wrap.children[0].cloneNode(true) var i = 0 //将克隆的元素加入到ul wrap.appendChild(firstLi) //封装一个autoMove的函数 function autoMove() { //切换图片的定时器 var timer = setInterval(() => { move(wrap, showWidth) }, 2000) } // //调用自动移动的方法 autoMove()//抽取方法 x轴移动 移动的元素 变化i值 移动的宽度 对应的方向(默认为正方向) function move(element, showWidth, isAsc = true) { if (isAsc) { i++ } else { i-- } //移动对应的ul 0 -400 -800 //距离等于 当前下标*对应显示盒子的宽度*-1 var distance = i * showWidth * -1 //执行动画 bufferAnimation(element, { left: distance }, () => { //到达最后下标 if (i == element.children.length - 1 && isAsc) { //i的值重新变成0 i = 0 } if (i == 0 && !isAsc) { //立即设置位置 到第一张设置位置为最后一张 i = element.children.length - 1 } //设置位置 element.style.left = i * showWidth * -1 + 'px' }) } </script> </body> </html>
升级版带焦点的轮播
- html代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } .showBox, li { width: 400px; height: 250px; } li>img {width: 100%; } .showBox { position: relative; margin: 200px auto; /* 溢出隐藏 */ overflow: hidden; } ul { width: 800%; position: relative; } ul>li { list-style: none; float: left; } .cirList { position: absolute; right: 20px; bottom: 10px; width: 150px; } .cirList>li { width: 10px; height: 10px; background-color: #fff; border-radius: 50%; margin: 0 5px; } .cirList .selected { background-color: red; } .arrow{ display: none; } .arrow>a{ display: block; width: 50px; height: 50px; position: absolute; top: 50%; margin-top: -25px; } .arrow>.prev{ background: url(./images/prev.png) no-repeat center; background-size: contain; left: 0; } .arrow>.next{ background: url(./images/next.png) no-repeat center; background-size: contain; right: 0; } </style> </head> <body> <div class="showBox"> <ul class="wrap"> <li><img src="./images/slidepic1.jpg" alt=""></li> <li><img src="./images/slidepic2.jpg" alt=""></li> <li><img src="./images/slidepic3.jpg" alt=""></li> <li><img src="./images/slidepic4.jpg" alt=""></li> <li><img src="./images/slidepic5.jpg" alt=""></li> <li><img src="./images/slidepic6.jpg" alt=""></li> <li><img src="./images/slidepic7.jpg" alt=""></li> </ul> <!-- 焦点 --> <ul class="cirList"> </ul> <div class="arrow"> <a href="" class="prev"></a> <a href="" class="next"></a> </div> </div> <script src="./move.js"></script> <script src="./carousel.js"></script> </body> </html>
- js代码
//获取显示盒子 var showBox = document.querySelector('.showBox') //获取显示盒子的宽度 var showWidth = parseFloat(getStyle(showBox).width) //获取ul(需要切换位置的容器) var wrap = document.querySelector('.wrap') //获取焦点的盒子 var cirList = document.querySelector('.cirList') //获取箭头的盒子 var arrow = document.querySelector('.arrow') //变化的下标 var i = 0 //焦点取值的下标 var index = 0 //定时器 var timer //调用init的方法 init() //调用自动移动的方法 autoMove() //给showBox添加移入事件 showBox.onmouseenter = function () { //清除定时器 clearInterval(timer) //显示箭头的盒子 arrow.style.display = 'block' } //移出继续执行 showBox.onmouseleave = function () { //调用轮播 autoMove() //隐藏 arrow.style.display = 'none' } //给箭头添加事件 Array.from(arrow.children).forEach((v, i) => { v.onclick = (e) => { e = e || window.event //禁止a标签默认行为 e.preventDefault(); move(wrap, showWidth, i) } }) //给cirList下面的li添加点击事件 事件委托机制 cirList.onclick = function (e) { e = e || window.event //判断当前操作的元素是否为li if (e.target.tagName == 'LI') { //获取当前点击的li的下标 let clcikIndex = Array.from(cirList.children).findIndex((v) => { //如果当前操作的对象是遍历的对象那么返回出去 return v == e.target })-1 //改变对应位置及下标 index = clcikIndex i = clcikIndex //调用move移动 move(wrap, showWidth) } } //初始化生成焦点的方法 function init() { //拷贝之前生成对应的焦点 Array.from(wrap.children).forEach((v, i) => { //在第一个焦点添加一个class名字为selected if (i == 0) { cirList.innerHTML += `<li class='selected'></li>` } else { //生成对应的焦点加入到cirList里面 cirList.innerHTML += `<li></li>` } }) //拷贝第一张图加到最后 //克隆第一个li var firstLi = wrap.children[0].cloneNode(true) //将克隆的元素加入到ul wrap.appendChild(firstLi) } //封装一个autoMove的函数 function autoMove() { //切换图片的定时器 timer = setInterval(() => { move(wrap, showWidth) }, 2000) } //封装一个焦点变化的函数 传入的index表示当前要设置的焦点 function changeCir(index) { //排他思维 //先将所有的class清除 Array.from(cirList.children).forEach((li) => { li.className = '' }) //再给自己添加对应的样式 cirList.children[index].className = 'selected' } //抽取方法 x轴移动 移动的元素 变化i值 移动的宽度 对应的方向(默认为正方向) function move(element, showWidth, isAsc = true) { //先检索区间 rangeCheck(element, isAsc) //再进行i值变化 if (isAsc) { i++ index++ } else { i-- index-- } //焦点切换及区间检索 rangeCheckCir(element) //执行动画 //移动对应的ul 0 -400 -800 //距离等于 当前下标*对应显示盒子的宽度*-1 var distance = i * showWidth * -1 bufferAnimation(element, { left: distance }, () => { }) } //区间检索i下标 function rangeCheck(element, isAsc) { //到达最后下标 if (i >= element.children.length - 1 && isAsc) { //i的值重新变成0 i = 0 } if (i <= 0 && !isAsc) { //立即设置位置 到第一张设置位置为最后一张 i = element.children.length - 1 } //设置位置 element.style.left = i * showWidth * -1 + 'px' } //区间检索对应的焦点下标值 function rangeCheckCir(element) { //判断焦点下标 if (index < 0) { //8张图 下标为 0-7 7个焦点 下标 0-6 index = element.children.length - 2 } if (index > element.children.length - 2) { index = 0 } //更改焦点 changeCir(index) }
辅助代码 (move.js)
//缓冲运动封装 //element表示当前的元素 target表示目标对象 callbackFn表示传入的回调函数 function bufferAnimation(element, targetObj,callbackFn) { //如果element为undefined就直接报错 if(!element){ throw new Error('元素不能缺少') } //清除上一个定时器影响 (保证只有一个定时器) clearInterval(element.timer) //给元素对象添加一个属性为timer他是一个定时器 element.timer = setInterval(() => { var flag = true //遍历对象 for (let key in targetObj) { //取出当前值 let current = parseFloat(getStyle(element)[key]) //取出目标值 let target = targetObj[key] //判断当前如果是位置的变化及对应的宽度高度的变化 if(key=='width' || key == 'height' || key == 'left' || key == 'top') { //步长 负值向下取整 正值向上取整 var step = target-current>0?Math.ceil((target - current) / 10):Math.floor((target - current) / 10) current += step element.style[key] = current + 'px' } //如果是透明度的变化 if(key == 'opacity'){ //步长 负值向下取整 正值向上取整 var step = target-current>0?Math.ceil((target - current) * 1000 / 10):Math.floor((target - current)*1000 / 10) current += step / 1000 element.style[key] = current } //如果是层高直接赋值 if(key == 'zIndex'){ element.style[key] = target } //如果没有完成就是false if(current != target){ flag = false } } //如果全部走完了就清除 if(flag){ clearInterval(element.timer) //调用回调函数 如果传入的参数是函数 if(typeof callbackFn == 'function'){ callbackFn() } } },0) } //封装一个方法获取对应的样式(获取所有的样式) function getStyle(element) { if (window.getComputedStyle) { return window.getComputedStyle(element, '') } else { return element.currentStyle } }
重点
-
逻辑的掌握
-
dom操作
-
定时器操作
-
错误的解决
-
定时器里面套定时器 ( 如果外面的执行时间要比里面的短 会导致里面的定时器无法被清除 (定时器
-
的作用范围内要清除对应的定时器) )
-
知识点的运用
-
封装 (函数封装 抽取共同点)
-
同步和异步 (通过回调函数解决 定时器是异步的 事件也是异步的)
第三方动画的js
move.js
github地址 : https://github.com/visionmedia/move.js
<div class="box"></div> <div class="mybox"></div> <script src='https://cdn.bootcdn.net/ajax/libs/move.js/0.5.0/move.js'></script> <script> move('.box') .to(500, 200) //位置改变 x为500 y为200 .rotate(180) //旋转180deg .scale(.5) //缩小0.5倍 .set('background-color', '#888')//背景颜色 .set('border-color', 'black')//边框颜色 .duration('2s')//执行时间 .skew(50, -10) //偏移 .then() //成功 // .set('opacity', 0) //透明度为0 .duration('0.3s') //时间 .scale(0.1) //缩小 .pop() //加上他才能执行颜色设置相关的内容 .end(); //动画结束 //背景颜色变成绿色 // 位置 变成 300 300 // 旋转 180deg // 上面做完 放大2倍 move('.mybox') .to(500,500) .set('background-color', 'hotpink') .rotate(180) .duration('3s') .then().scale(2).duration('11s').pop().end() </script>animated.css (封装了css3的动画效果) 官网 : https://animate.style/ swiper.js (封装轮播图) 官网:https://www.swiper.com.cn/index.html
标签:index,轮播,笔记,element,current,day17,showBox,key,var From: https://www.cnblogs.com/itlulu/p/16823004.html