通过前面几篇文章的讲解,相信你们已经会操做DOM
和BOM
了。为何前面要花那么多精力去讲DOM
呢?由于在后面的学习、工做中,会大量的使用DOM
操做,一个表格须要增、删、改、查,一个图片须要改变大小..等,若是你想要动态的改变这些,必需要学会使用DOM
。javascript
为了巩固前面的知识点,而且可以熟练地使用它们,这里单独写了一篇《JavaScript 进阶知识 - 特效篇》。本篇文章做为进阶篇很重要,不仅仅是对前面知识点的运用,期间也会有大量的新知识点注入,因此但愿小伙伴们继续加油,认真阅读。css
在本篇文章中主要会讲解一些案例,好比咱们平时在页面中碰到的一些特效,一些动画效果。html
注意: 全部的案例都在这里连接: 提取密码密码: 70ny
,文章中的每一个案例后面都有对应的序号。java
offset
系列用于用于获取元素自身的大小和位置,在网页特效中有普遍应用。offset
系列主要有:offsetHeight
、offsetWidth
、offsetParent
、offsetLeft
、offsetTop
。
offsetWidth
和offsetHeight
获取的是元素的真实宽高
offsetHeight
与offsetWidth
是只读属性,不能设置。示例代码:获取一个盒子的真实宽高 [01-offset系列-offsetWidth&Height.html]面试
<!-- 样式部分 --> <style> div { width: 200px; height: 100px; background-color: pink; padding: 10px; border: 10px solid salmon; margin: 10px; } </style> <!-- html 部分 --> <div id="box"></div> <!-- js 部分 --> <script> var box = document.getElementById('box'); // offsetWidth是一个经过计算后获得的值, padding + border + width console.log(box.offsetWidth); // 240 console.log(box.offsetHeight); // 140 </script>
offsetWidth
是一个经过计算后获得的值, padding
+ border
+ width
segmentfault
思考: 以前咱们不是也能够经过style
来获取样式吗?他们有什么不一样数组
style.height
与style.width
只能获取到行内样式里的width
和height
总结:浏览器
style.width
与style.height
offsetWidth
与offsetHeight
offset
获取的宽高包括padding
、border
parentNode
和offsetParent
parentNode
始终是父元素offsetParent
是离当前元素最近的定位元素(absolute
、relative
),若是没有,那就找body
示例代码: [02-offset系列-offsetParent.html]app
<!-- 样式部分 --> <style> #father { width: 500px; height: 500px; background-color: #FF9F68; } #son { width: 300px; height: 300px; background-color: #FEFF89; } #grandson { width: 100px; height: 100px; background-color: #AC005D; position: absolute; left: 100px; right: 100px; } </style> <!-- html 部分 --> <div id="father"> <div id="son"> <div id="grandson"></div> </div> </div> <!-- js 部分 --> <script> var grandSon = document.getElementById("grandson"); // 找父节点 亲爹 console.log(grandSon.parentNode); // 返回<div id="son"></div> // 找最近有定位的爹,若是找不到,会找body console.log(grandSon.offsetParent); // 返回<body></body> </script>
offsetLeft
: 自身左侧到offsetParent
左侧的距离:left + margin
offsetTop
: 自身顶部到offsetParent
顶部的距离 :top + margin
框架
offsetParent
真实的距离示例代码:获取一个盒子距父盒子的距离 [03-offset系列-offsetTop&Left.html]
<!-- 样式部分 --> <style> #father { width: 400px; height: 400px; background-color: pink; position: relative; margin-left: 100px; } #son { width: 200px; height: 200px; background-color: skyblue; position: absolute; left: 100px; margin: 20px; } </style> <!-- html 部分 --> <div id="father"> <div id="son"></div> </div> <!-- js 部分 --> <script> //offsetLeft与offsetTop var son = document.getElementById("son"); console.log(son.offsetLeft); // 120 console.log(son.offsetTop); // 20 </script>
思考: 以前咱们不是也能够经过style
来获取样式吗?他们有什么不一样
style.top
与style.left
只能获取到行内样式里的top
和left
总结:
left/top
使用style.left
与style.top
left/top
使用offsetLeft
与offsetTop
offset
获取的位置包括margin
body
的一张图看清offset系列
如何让一个物体动起来?动画函数的实现原理其实就是利用间歇定时器每隔一段时间执行一次的原理实现的。
一、让一个物体动起来
点击按钮让一个盒子匀速往右执行一段距离:[04-匀速动画初体验(一).html]
<!-- 样式部分 --> <style> * { margin: 0; padding: 0; } #box { width: 100px; height: 100px; background-color: hotpink; position: absolute; } </style> <!-- html 部分 --> <button id="btn">奔跑吧</button> <div id="box"></div> <!-- js 部分 --> <script> var btn = document.getElementById('btn'); var box = document.getElementById('box'); btn.onclick = function() { setInterval(function() { // 定义一个距离 至关于每一次要跑的距离 step var step = 5; // 定义一个当前位置 leader var leader = box.offsetLeft; // 每次执行的时候 让leader都走step距离 leader = leader + step; // 将距离赋值给box box.style.left = leader + "px"; // 每15ms 就执行一次 人眼视觉停留 就有动画效果了 }, 15); } </script>
效果图:
BUG: 不知道细心的小伙伴有没有发现两个问题
二、让一个物体动起来,解决bug
咱们让盒子运动到500px
的位置停下来 [05-匀速动画初体验(二).html]
var btn = document.getElementById('btn'); var box = document.getElementById('box'); var timer = null; /** 为何会越点越快? 点击一次就会调用一次定时器,点击的次数越多,调用的就越多 距离叠加的就会愈来愈大 视觉效果上看起来就跑的愈来愈快 只要在每次点击后,定时器执行前清除上一次定时器,就不会出现越点越快的效果了 */ btn.onclick = function() { // 一进来就清除定时器 clearInterval(timer); timer = setInterval(function() { // 定义一个距离 至关于每一次要跑的距离 step var step = 5; // 定义一个当前位置 leader var leader = box.offsetLeft; /** 当移动的位置在500px内的时候,执行动画函数 不然就清除定时器,让盒子停下来 */ if (leader < 500) { // 每次执行的时候 让leader都走step距离 leader = leader + step; // 将距离赋值给box box.style.left = leader + "px"; } else { clearInterval(timer); } }, 15); }
效果图:
总结:
setInterval
间歇定时器,若是不手动清除,它就会一直运行下去函数须要独立,就不能使用全局变量。timer
以前是一个全局变量,若是不独立,页面只有一个定时器在运做。封装的函数里将timer
绑定给调用定时器的元素,这样就独立了。
一、封装一个动画函数 [06-封装一个匀速动画函数.html]
<!-- html 部分 --> <button id="btn">奔跑吧,500</button> <button id="btn2">奔跑吧,1000</button> <div id="box"></div> <!-- js 部分 --> <script> var btn = document.getElementById('btn'); var btn2 = document.getElementById('btn2'); var box = document.getElementById('box'); /** 既然是封装的函数,有些不肯定的,常常变的元素就要提出来 好比: 1.每一次改变的距离 num 2.调用动画的对象 box ==> element 3.运动的目标距离 500 ==> target */ // 封装一个动画函数 function animate(element, target,num) { // 一进来就清除定时器 // 函数须要独立,就不能使用全局变量 因此将timer绑定在element上 clearInterval(element.timer); element.timer = setInterval(function() { // 定义一个距离 至关于每一次要跑的距离 step var step = num; // 定义一个当前位置 leader var leader = element.offsetLeft; if (leader < target) { // 每次执行的时候 让leader都走step距离 leader = leader + step; // 将距离赋值给box element.style.left = leader + "px"; } else { clearInterval(element.timer); } }, 15); } // 点击按钮1 移动到500px的位置 btn.onclick = function() { animate(box, 500, 9); } // 点击按钮2 移动到1000px的位置 btn2.onclick = function() { animate(box, 1000, 5); } </script>
注意: 上面的案例咱们只是简单的实现了一个动画的封装效果,可是做为一个之后会常常用的函数,上面的代码还有不少须要优化的地方
1000
,想让它回到500
是很差实现的;5
,目标距离是500
,正好能整除。假如每次走的是9
呢?每次走9
,是不能被500
整除的,因此最后停下里的距离会偏多一点。二、封装一个动画函数完整版 [07-封装一个匀速动画函数完整版.html]
clearInterval(element.timer); // 清除前位置在504,直接在下面设置让它位置等于500 element.style.left = target + "px"; // 500
1000
的时候不能回到500
。假设如今盒子在1000
,咱们点击按钮1
的时候想要让他回到500
,这个时候咱们能够发现时的leader = 1000
,目标距离target为500
,就是说当leader>target
的时候,盒子是能够往回走的,这时候只要将步数设置为负数
,盒子就是往回跑的。var leader = element.offsetLeft; // 当目标距离大于当前位置 说明往正方向走 step的值就是正的 var step = target > leader? 9 : -9;
if (leader < target){}, else { clearInterval(element.timer); }
去判断,让盒子运动了。这时的判断条件应该是目标距离target
与盒子目前距离leader
之间差的绝对值大于等于一步距离step
绝对值的时候,让他们执行leader = leader + step;
不然的话清除清除定时器,并将最后的距离直接设置为target
的距离。var distance = Math.abs(target - leader); // 经过判断此时的差若是大于或者等于一步的距离step的时候,就应该执行动画 if (distance >= Math.abs(step)) { leader = leader + step; element.style.left = leader + "px"; }
完整代码:
<!-- html 部分 --> <button id="btn">奔跑吧,500</button> <button id="btn2">奔跑吧,1000</button> <div id="box"></div> <!-- js 部分 --> <script> var btn = document.getElementById('btn'); var btn2 = document.getElementById('btn2'); var box = document.getElementById('box'); function animate(element, target, num) { clearInterval(element.timer); element.timer = setInterval(function() { var leader = element.offsetLeft; // 判断此时每次走的距离,当目标距离大于当前位置 说明往正方向走 step的值就是正的 var step = target > leader ? num : -num; // 得到此时的距离 与目标距离的差的绝对值 var distance = Math.abs(target - leader); // 经过判断此时的差若是大于或者等于一步的距离step的时候,就应该执行动画 if (distance >= Math.abs(step)) { leader = leader + step; element.style.left = leader + "px"; } else { // 不然清除动画,而且将最后的距离设置为target的距离 clearInterval(element.timer); element.style.left = target + "px"; } }, 15); } btn.onclick = function() { animate(box, 500, 9); } btn2.onclick = function() { animate(box, 1000, 5); } </script>
效果图:
如上,这就是封装的一个完美的动画函数了,下次有须要用到动画的地方,直接引用便可——[ js/animate.js ]
基本上每一个网站都会用到轮播图,轮播图的使用能够说是必不可少的。之后咱们用的最多的多是插件,原生的可能并不经常使用,可是轮播图的原理咱们必须知道,而且可以写出来。(以前一次面试就是让我讲出轮播图的具体实现步骤)
如今咱们先来学习下简单的轮播图实现原理。
轮播图样式的特色:
ul
要足够的宽,要求可以一行放下全部的li
overflow:hidden
,仅显示一张图片,很少很多要求ul
很宽很宽,由于全部的li
要左浮动,要保证全部的li
在一行上显示,定义一个盒子,盒子的宽高要和显示的单张图片宽高同样,而后设置overflow:hidden
这样其余的li
就会被隐藏在下面,经过改变ul的位置就能实现图片的切换了
示例代码: [08-实现简单的轮播图.html]
<!-- 样式部分 --> <style> * { margin: 0; padding: 0; list-style: none; } #slide { width: 560px; height: 315px; margin: 100px auto; position: relative; overflow: hidden; } #slide ul { width: 600%; position: absolute; } #slide ul li { float: left; } #slide ul img { display: block; } #slide ol { width: 100px; height: 14px; background-color: rgba(255, 255, 255, .6); /* background-color: pink; */ position: absolute; bottom: 14px; left: 50%; margin-left: -50px; border-radius: 7px; } #slide ol li { width: 10px; height: 10px; float: left; background-color: #fff; border-radius: 50%; margin-top: 2px; margin-left: 8.5px; cursor: pointer; } #slide ol li.current { background-color: #DF654A; } </style> <!-- html 部分 --> <div id="slide"> <ul> <li> <a href="#"><img src="../image/1.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/2.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/3.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/4.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/5.jpg" alt=""></a> </li> </ul> <ol> <li class="current"></li> <li></li> <li></li> <li></li> <li></li> </ol> </div> <!-- js 部分 --> <script src="../js/animate.js"></script> <script> var slide = document.getElementById('slide'); var ul = slide.children[0]; var ol = slide.children[1]; // ol 下的 li 小圆点 var lis = ol.children; var imgWidth = slide.offsetWidth; // 给全部的小圆点注册点击事件 for (var i = 0; i < lis.length; i++) { lis[i].index = i; lis[i].onclick = function() { // 小圆点高亮排他 for (var i = 0; i < lis.length; i++) { lis[i].className = ""; } this.className = "current"; // 点击小圆点,让对应的图片轮播 获取ul要改变的距离 // 负的表示ul 向左运动 此时小圆点对应的索引乘以盒子的宽度 就是ul要移动的宽度 var target = -this.index * imgWidth; // ul.style.left = target + 'px'; // 让图片像动画同样慢慢的移过去 animate(ul, target, 50); } } </script>
效果图:
从上面效果图中,咱们能够看到,一个最简单的轮播图已经成型了,可是须要去用手点击,并且若是跨点数去点击,会发现图片要一张张滑过去,这里后面咱们会优化。
左右焦点轮播图,就是在显示图片的两端添加两个按钮,一个向左,一个向右,点击的时候图片会根据点击的方向滑动。而且当鼠标悬停在显示区域的时候,两个按钮显示。鼠标离开显示区域,,两个按钮隐藏。
示例代码: [09-左右焦点轮播图.html]
<!-- 样式部分 --> <style> * { margin: 0; padding: 0; list-style: none; } #slide { width: 560px; height: 315px; margin: 100px auto; position: relative; overflow: hidden; } #slide ul { width: 600%; position: absolute; } #slide ul li { float: left; } #slide ul img { display: block; } #slide #arrow { display: none; } #slide #arrow #leftArr, #slide #arrow #rightArr { width: 30px; height: 60px; background-color: rgba(255, 255, 2550, 0.3); position: absolute; top: 50%; margin-top: -30px; text-decoration: none; color: #fff; text-align: center; font: 700 24px/60px "宋体"; } #slide #arrow #leftArr { left: 0; } #slide #arrow #rightArr { right: 0; } </style> <!-- html 部分 --> <div id="slide"> <ul> <li> <a href="#"><img src="../image/1.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/2.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/3.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/4.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/5.jpg" alt=""></a> </li> </ul> <div id="arrow"> <a href="javascript:void(0);" id="leftArr"><</a> <a href="javascript:void(0);" id="rightArr">></a> </div> </div> <!-- js 部分 --> <script src="../js/animate.js"></script> <script> var slide = document.getElementById('slide'); var ul = slide.children[0]; var lis = ul.children; var arrow = document.getElementById('arrow'); var leftArr = document.getElementById("leftArr"); var rightArr = document.getElementById("rightArr"); var imgWidth = slide.offsetWidth; // 给slide注册鼠标通过事件,鼠标通过时 显示arrow slide.onmouseover = function() { arrow.style.display = "block"; }; // 给slide注册鼠标离开事件,鼠标离开时 隐藏arrow slide.onmouseout = function() { arrow.style.display = "none"; }; // 点击右箭头 var count = 0; // 跑出去的张数 rightArr.onclick = function() { // 当这个张数不等于最后一张的时候 执行动画 if (count < lis.length - 1) { count++; var target = -count * imgWidth; animate(ul, target, 40); } } leftArr.onclick = function() { // 当这个张数不等于最后一张的时候 执行动画 if (count > 0) { count--; var target = -count * imgWidth; animate(ul, target, 40); } } </script>
效果图:
上图能够看到,当滑到最左边或者最右边的时候,再点击就没有用了,正常的轮播图确定不是这样的,点击到最后一张后再点击确定是接着滑动的。下面咱们接着看,如何实现一个无缝轮播图
示例代码:无缝轮播(能够一直点击) [10-左右焦点轮播图-无缝滚动.html]
何谓无缝滚动?
无缝滚动就是图片可以循环切换,就算是最后一张,点击以后也会跳到第一张
原理:
示例代码:无缝滚动的简单原理 [10-无缝滚动原理.html]
<!-- 样式部分 --> <style> * { margin: 0; padding: 0; list-style: none; } #slide { position: relative; width: 560px; height: 315px; border: 6px dashed #CBF078; margin: 100px auto; overflow: hidden; } #slide ul { width: 3360px; position: absolute; left: 0; top: 0; } #slide ul li { float: left; } #slide ul li img { display: block; vertical-align: top; } </style> <!-- html 部分 --> <div id="slide"> <ul> <li> <img src="../image/1.jpg" alt=""> </li> <li> <img src="../image/2.jpg" alt=""> </li> <li> <img src="../image/3.jpg" alt=""> </li> <li> <img src="../image/4.jpg" alt=""> </li> <li> <img src="../image/5.jpg" alt=""> </li> <!-- 添加一张与第一张如出一辙的图片 障眼法 --> <li> <img src="../image/1.jpg" alt=""> </li> </ul> </div> <!-- js 部分 --> <script> var slide = document.getElementById('slide'); var ul = slide.children[0]; setInterval(function() { // 每次向左移动的距离 var step = -3; // 获取 ul的left的值 是个负值 var leader = ul.offsetLeft; // 定义一个目标距离,这里的目标距离指的是最后一张图片距离左边的left值 // 图片宽度560 在最后一张距离左边left的位置:-560*5 = -2800 // 就是说当到达这张图片的时候就应该让 ul.style.left = "0px"; var target = -2800; // 为何不直接判断 leader = -2800的时候让ul.style.left = "0px";? // 由于每次走3步 3不能被2800整除,因此leader永远不会等于-2800的 // 这里直接判断leader此时距左边的距离减去目标距离当这个绝对值大于等于 一步距离的绝对值3的时候让它执行往左运动 if (Math.abs(leader - target) >= Math.abs(step)) { leader = leader + step; ul.style.left = leader + "px"; // 当不足一步距离的时候说明就是最后一张了,就应该跳到第一张图片了 } else { ul.style.left = "0px"; } }, 15); </script>
效果图:
左右焦点无缝轮播图: [11-左右焦点无缝轮播图.html]
<!-- 样式部分 --> <style> * { margin: 0; padding: 0; list-style: none; } #slide { width: 560px; height: 315px; margin: 100px auto; position: relative; overflow: hidden; } #slide ul { width: 600%; position: absolute; } #slide ul li { float: left; } #slide ul img { display: block; } #slide #arrow { display: none; } #slide #arrow #leftArr, #slide #arrow #rightArr { width: 30px; height: 60px; background-color: rgba(255, 255, 2550, 0.3); position: absolute; top: 50%; margin-top: -30px; text-decoration: none; color: #fff; text-align: center; font: 700 24px/60px "宋体"; } #slide #arrow #leftArr { left: 0; } #slide #arrow #rightArr { right: 0; } </style> <!-- html 部分--> <div id="slide"> <ul> <li> <a href="#"><img src="../image/1.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/2.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/3.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/4.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/5.jpg" alt=""></a> </li> <!-- 添加一张图片 障眼法 --> <li> <a href="#"><img src="../image/1.jpg" alt=""></a> </li> </ul> <div id="arrow"> <a href="javascript:void(0);" id="leftArr"><</a> <a href="javascript:void(0);" id="rightArr">></a> </div> </div> <!-- js 部分 --> <script src="../js/animate.js"></script> <script> var slide = document.getElementById('slide'); var ul = slide.children[0]; var lis = ul.children; var arrow = document.getElementById('arrow'); var leftArr = document.getElementById("leftArr"); var rightArr = document.getElementById("rightArr"); var imgWidth = slide.offsetWidth; // 给slide注册鼠标通过事件,鼠标通过时 显示arrow slide.onmouseover = function() { arrow.style.display = "block"; }; // 给slide注册鼠标离开事件,鼠标离开时 隐藏arrow slide.onmouseout = function() { arrow.style.display = "none"; }; // 点击右箭头 var count = 0; // 跑出去的张数 rightArr.onclick = function() { // 当这个张数等于最后一张的时候,偷偷摸摸的把最后一张图片换成第一张 if (count == lis.length - 1) { count = 0; ul.style.left = 0; } count++; var target = -count * imgWidth; animate(ul, target, 40); } leftArr.onclick = function() { // 判断是第一张的时候,偷偷摸摸的把第一张换成最后一张 if (count == 0) { count = lis.length - 1; ul.style.left = -count * imgWidth + "px"; } count--; var target = -count * imgWidth; animate(ul, target, 40); } </script>
效果图:
前面咱们已经能够经过点击对应的小点、左右焦点和无缝滚动来实现轮播图了,不过都是单独分开来的,如今咱们作个整合,实现一个完整的轮播图。
功能概述:
简单轮播功能
circle
下的全部的li注册点击事件Ul
左右焦点功能
count
来记录移动的图片的张数。点击右箭头功能
count
的小圆点。点击左箭头的功能和右箭头基本一致。
自动轮播的功能
ul
,若是给ul
注册事件,就会出现乱闪的问题 同步功能
bug
解决方法(当一圈事后回到第一个小圆点的时候,再点击它会发现他会再跑一圈)完整代码: [12-完整版轮播图.html]
<!-- 样式部分 --> <style> * { margin: 0; padding: 0; list-style: none; } #slide { width: 560px; height: 315px; margin: 100px auto; position: relative; overflow: hidden; } #slide ul { width: 600%; position: absolute; } #slide ul li { float: left; } #slide ul img { display: block; } #slide #arrow { display: none; } #slide #arrow #leftArr, #slide #arrow #rightArr { width: 30px; height: 60px; background-color: rgba(0, 0, 0, 0.5); position: absolute; top: 50%; margin-top: -30px; text-decoration: none; color: #fff; text-align: center; font: 700 24px/60px "宋体"; } #slide #arrow #leftArr { left: 0; } #slide #arrow #rightArr { right: 0; } #slide ol { width: 100px; height: 14px; background-color: rgba(255, 255, 255, .6); /* background-color: pink; */ position: absolute; bottom: 14px; left: 50%; margin-left: -50px; border-radius: 7px; } #slide ol li { width: 10px; height: 10px; float: left; background-color: #fff; border-radius: 50%; margin-top: 2px; margin-left: 8.5px; cursor: pointer; } #slide ol li.current { background-color: #DF654A; } </style> <!--html 部分--> <div id="slide"> <ul> <li> <a href="#"><img src="../image/1.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/2.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/3.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/4.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/5.jpg" alt=""></a> </li> <li> <a href="#"><img src="../image/1.jpg" alt=""></a> </li> </ul> <!-- 左右箭头 --> <div id="arrow"> <a href="javascript:void(0);" id="leftArr"><</a> <a href="javascript:void(0);" id="rightArr">></a> </div> <!-- 小圆点 --> <ol id="circleOl"> <li class="current"></li> <li></li> <li></li> <li></li> <li></li> </ol> </div> <script src="../js/animate.js"></script> <script> // 自执行函数,防止页面其余定时器会受影响 (function() { var slide = document.getElementById('slide'); var imgUl = slide.children[0]; var imgLis = imgUl.children; var arrow = document.getElementById('arrow'); var leftArr = document.getElementById("leftArr"); var rightArr = document.getElementById("rightArr"); var circleOl = document.getElementById('circleOl'); var circleLis = circleOl.children; // 获取图片的宽度 var imgWidth = slide.offsetWidth; var timer = null; // 点击小圆点改变对应图片 for (var i = 0; i < circleLis.length; i++) { circleLis[i].index = i; circleLis[i].onclick = function() { // 小圆点点击的时候高亮排他 for (var i = 0; i < circleLis.length; i++) { circleLis[i].className = ""; } this.className = "current"; // 淘宝bug:这时还须要判断一下 就是当图片在最后一张假图片的时候, // 再去点击第一个小圆点的时候,会出现一个bug,就是图片会轮播一圈再回到这张图片上 if (count == imgLis.length - 1) { count = 0; imgUl.style.left = 0; } // 点击小圆点图片要移动 var target = -this.index * imgWidth; // 若是这里不记录一下,当点击小圆点跳到某张图片的时候,再自动播放的时候, // 不会接着当前小圆点的位置日后播放,而是接着以前count不变的状况下 继续播放的 count = this.index; animate(imgUl, target, 40); } } // 左右焦点轮播图 var count = 0; // 跑出去的张数 rightArr.onclick = function() { // 当这个张数等于最后一张(假图片)的时候,偷偷摸摸的把最后一张图片换成第一张 if (count == imgLis.length - 1) { count = 0; imgUl.style.left = 0; } // 点击一次图片向右划动一次 count++; var target = -count * imgWidth; animate(imgUl, target, 40); //让小圆点跟着动 只要将 count 与小圆点绑定便可 for (var i = 0; i < circleLis.length; i++) { circleLis[i].className = ""; } // 这里须要判断一下 由于此时最后一张是假图片 小圆点是不能正常跳转到第一个的 // 当count == 最后一张图片的下标的时候,直接让第一个小圆点亮 if (count == imgLis.length - 1) { circleLis[0].className = "current"; } else { // 不然其余的下标对应的小圆点高亮 circleLis[count].className = "current"; } } leftArr.onclick = function() { // 判断是第一张的时候,偷偷摸摸的把第一张换成最后一张 if (count == 0) { count = imgLis.length - 1; imgUl.style.left = -count * imgWidth + "px"; } count--; var target = -count * imgWidth; animate(imgUl, target, 40); // 小圆点同步 往左的时候不会出现小圆点不一样步的问题 for (var i = 0; i < circleLis.length; i++) { circleLis[i].className = ""; } circleLis[count].className = "current"; } timer = setInterval(function() { rightArr.onclick(); }, 2000); // 给slide注册鼠标通过事件,鼠标通过时 显示arrow slide.onmouseover = function() { arrow.style.display = "block"; // 鼠标通过图片的时候清除定时器,中止轮播 clearInterval(timer); }; // 给slide注册鼠标离开事件,鼠标离开时 隐藏arrow slide.onmouseout = function() { arrow.style.display = "none"; // 鼠标离开图片的时候开启定时器,自动轮播 timer = setInterval(function() { rightArr.onclick(); }, 2000); }; })()
轮播图的一些功能可能有点绕,写的有可能不太看得懂,有疑惑的小伙伴直接私信我,我会一步步解释给你听的,有什么bug
也能够将代码发给我。
想为后面打下扎实的基础的话,这里必定要多敲几遍,主要要搞明白的是实现的思路,以及一些小bug
的解决。这对后面的学习是很是重要的。代码备注可能读起来有些拗口,不懂得小伙伴直接私信给我。
缓动动画,顾名思义,就是愈来愈慢的运动。
咱们先来回顾一下上面匀速动画运动的原理:
/** step : 一步的距离 leader :当前的距离 咱们能够看到 step在这里一直等于5 未曾改变 因此就是匀速运动 */ var step = 5; leader = leader + step;
如今咱们再来看下缓动动画的原理:
/** target: 目标距离,盒子运动到什么地方 step : 一样的,仍是指每次运动的距离,可是这里的步数是一个变化的量了, 咱们能够看到它会随着leader的增长变得愈来愈小,这就是缓动动画的原理 leader: 当前的距离 */ var step = (target - leader)/10; leader = leader + step;
示例代码: [13-缓动动画初体验(一).html]
<!-- 样式部分 --> <style> * { margin: 0; padding: 0; } #box { width: 100px; height: 100px; position: absolute; background: orange; } </style> <!-- html 部分--> <input type="button" value="奔跑吧" id="btn"> <div id="box"></div> <!-- js 部分 --> <script> var box = document.getElementById('box'); var btn = document.getElementById('btn'); var timer = null; btn.onclick = function() { clearInterval(timer); timer = setInterval(function() { // 定义一个目标距离 var target = 600; // 得到当前盒子的位置 var leader = box.offsetLeft; // 每次运动的距离 var step = (target - leader) / 10; // leader = leader + step 动起来 leader += step; // 将距离给盒子 box.style.left = leader + "px"; // 当当前距离等于目标距离的时候清除定时器 if (leader == target) { clearInterval(timer); } }, 15); } </script>
效果图:
完美了吗?并无,这里有个小bug:
可能会有小伙伴不理解,有问题你上面直接讲一下不就得了,还特意卖关子在下面从新写一遍。我想跟你们说的一点就是,若是在上面我直接告诉你这里有个问题有个bug的话,你一眼看过,可能都不当回事,我在这里拿出来说一下,相信这个知识点你会记得更深。
小bug:明明设置的是600
,怎么会是596.4px
呢?
缘由:
offsetLeft
获取值的时候,只会获取整数,会对小数部分会四舍五入处理,好比step = (target - leader)/10
当step
的值出现小数的时候,leader+= step
以后,offsetLeft
在获取leader
位置的时候就会把小数部分四舍五入,这样就会形成最后距离的偏差。解决方法:
step
向上取整处理(Math.ceil()
),保证每一次都至少跑1px
的距离,只要不出现小数offsetLeft
就不会出现四舍五入。完整代码: [14-缓动动画初体验(二).html]
var box = document.getElementById('box'); var btn = document.getElementById('btn'); var timer = null; btn.onclick = function() { clearInterval(timer); timer = setInterval(function() { // 定义一个目标距离 var target = 600; // 得到当前盒子的位置 var leader = box.offsetLeft; // 每次运动的距离 var step = (target - leader) / 10; // 对step进行向上取整 step = Math.ceil(step); // leader = leader + step 动起来 leader += step; // 将距离给盒子 box.style.left = leader + "px"; // 当当前距离等于目标距离的时候清除定时器 if (leader == target) { clearInterval(timer); } }, 15); }
前面匀速动画那里已经讲过封装一个函数的好处与重要性,如今咱们将缓动动画也封装成一个函数。
示例代码: [15-缓动动画函数封装.html]
<!-- 样式部分 --> <style> * { margin: 0; padding: 0; } #box { width: 100px; height: 100px; background: orange; position: absolute; } </style> <!-- html 部分 --> <input type="button" value="奔跑吧500" id="btn1"> <input type="button" value="奔跑吧1000" id="btn2"> <div id="box"></div> <!-- js 部分 --> <script> var btn1 = document.getElementById('btn1'); var btn2 = document.getElementById('btn2'); var box = document.getElementById('box'); // 缓动动画函数 /** element : 执行动画元素 target : 目标距离 num : 用来控制动画执行的速度 越大动画执行越慢 */ function slowAnimate(element, target, num) { // 一进来就要清除定时器,防止越点越快 clearInterval(element.timer); element.timer = setInterval(function() { // 得到元素当前位置 var leader = element.offsetLeft; // 定义每次运动的距离 var step = (target - leader) / num; // step多是小数 因此要取整 step = Math.ceil(step); leader += step; // 设置元素的位置 element.style.left = leader + 'px'; // 当元素的位置 等于 目标位置的时候 清除定时器 if (leader == target) { clearInterval(element.timer); } }, 15); } // 调用缓动动画函数 btn1.onclick = function() { slowAnimate(box, 500, 10); } // 一样是运动500的距离,咱们能够发现从500到1000,明显执行的比从0-500执行的慢 btn2.onclick = function() { slowAnimate(box, 1000, 30); } </script>
效果图:
又到了找bug的时候了:
上面的代码从0-500
,从500-1000
都没有问题,通过向上取整后都能到达目标距离:500
和1000
。可是小伙伴能够看下,当从1000
回到500
的时候,是正好回到500
的吗?答案确定不是的,为何呢?
step
为正数的时候,向上取整是彻底没有问题的,可是当从1000
到500
的时候,step
就是负数了,负数向上取整后就会变得更大,好比本来是-33.3
,向上取整后就是-33
了,-0.3
就会舍去,全部就不会到500
的位置。
解决方法: 判断step的正负,为正的时候,向上取整。为负的时候,向下取整。
缓动函数封装完整版: [16-缓动动画函数封装完整版.html]
function slowAnimate(element, target, num) { // 一进来就要清除定时器,防止越点越快 clearInterval(element.timer); element.timer = setInterval(function() { // 得到元素当前位置 var leader = element.offsetLeft; // 定义每次运动的距离 var step = (target - leader) / num; //若是step是正数,对step向上取整, //若是step是负数,对step向下取整 // 保证每一次最少都走1px step = step > 0 ? Math.ceil(step) : Math.floor(step); leader += step; // 设置元素的位置 element.style.left = leader + 'px'; // 当元素的位置 等于 目标位置的时候 清除定时器 if (leader == target) { clearInterval(element.timer); } }, 15); };
获取元素计算后的样式指的是元素通过层叠后真正生效的样式,无论样式写在哪,计算后的样式指的就是最终的样式。
经过style
只能获取到写在行内的样式,那么想要获取其余的样式怎么办呢?
window.getComputedStyle(element, null)[attr];
,它返回的是一个对象CSSStyleDeclaration
,[attr]
就是这个对象里面就是计算后的全部的样式的属性名(关联数组取对象的值)。element
指的是当前参数,null
这里能够不用深究-官方解释。这个方法须要window
调用。
/** element :获取样式的当前元素 null :这里能够传一个伪元素,若是不是伪元素的话必须是null attr :后面能够写具体的属性,好比boderRadius 就会获取这个元素的border-radius样式信息 */ window.getComputedStyle(element,null)[attr];
示例代码: [17-获取元素计算后的样式.html]
<!-- 样式部分 --> <style> div { width: 100px; height: 100px; background: pink; } #box { width: 200px; } </style> <!-- html 部分 --> <div id="box" style="width:300px;"></div> <!-- js 部分 --> <script> var box = document.getElementById('box'); console.log(window.getComputedStyle(box, null)); // 打印得到box的各类属性的样式 // 其中行内样式权重最高,因此最后得到的宽应该是300px console.log(window.getComputedStyle(box, null).width); // 300px console.log(window.getComputedStyle(box, null).background); </script>
效果图:
兼容性处理:
window.getComputedStyle(element, null)[attr];
只适用于现代浏览器中IE678
有本身的方法:element.currentStyle[attr];
// 获取元素计算后的样式 function getStyle(element,attr){ if(window.getComputedStyle){ return window.getComputedStyle(element, null)[attr]; }else{ return element.currentStyle[attr]; } } // 注意:调用函数的时候 获取的属性名是一个字符串 alert(getStyle(box, "width"));
[18-获取元素计算后的样式兼容性处理.html]
注意: 上面的封装函数中,调用的时候,属性名是一个字符串类型。
无论是上面的匀速动画函数,仍是这里的缓动动画函数,都只能左右运动,可是一个真正完整的动画函数,只改变左右位置确定是不够的,咱们可能须要改变它的宽高等。在上面一节中,咱们知道了如何获取到元素计算后的样式,并且只要是元素有的样式都能获取到,有了这个方法咱们就可让动画去执行更多的事情了。
一、对获取到的样式返回值进行处理:
在上面的一节中,咱们能够看到,获取的返回值都是字符串格式,好比获取宽度的时候,返回的是一个"300px"
的字符串,由于缓动动画函数里面是须要计算的,这里是个字符串确定不行,因此咱们须要对其进行parseInt
取整处理。
[19-缓动动画修改多个样式-处理返回值.html]:
function getStyle(element, attr) { if (window.getComputedStyle) { return window.getComputedStyle(element, null)[attr]; } else { return element.currentStyle[attr]; } } function animate(element, attr, target) { clearInterval(element.timer); element.timer = setInterval(function() { // getStyle 返回的是样式属性的值 咱们用一个变量将它储存起来 var leader = getStyle(element, attr); // 由于返回值是一个字符串,而且带有字符px,因此咱们对返回值进行取整转换 leader = parseInt(leader) || 0; // 这里或 0的目的就是,当parseInt取整失败的话,给一个默认值0 var step = (target - leader) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); leader += step; // 设置指定样式 element.style[attr] = leader + "px"; if (leader == target) { clearInterval(element.timer); } }, 15); } animate(box, "left", 800);
上面的代码咱们对它的返回值进行了处理,并且还能够对它设置其余的样式,只要单位是px
的属性均可以设置。可是这里每次仍是只能设置一个样式,下面咱们来实现修改多个样式。
注意: leader = parseInt(leader) || 0;
"或"上0
的目的就是:当有些属性设置的值不是数字的时候,好比:auto
,这时候parseInt
转换的结果是NaN
。当"或"上0
以后,转换失败后,leader
,就会默认是0
。
二、遍历一个对象:
让咱们来复习一下,js基础的时候,咱们接触到了对象,而且知道了能够用for..in
的方法来遍历对象。咱们知道getComputedStyle
方法,获取计算后样式的时候,返回的是一个名叫CSSStyleDeclaration
的对象,这个对象里面是全部的样式属性,咱们想要对这些属性进行多个操做的时候,就能够经过遍历的方法。
for(k in obj){ // k :就是至关于对象的键 // obj :就是须要遍历的对象 }
三、同时修改多个样式:
同时修改多个样式,就是将要修改的多个属性以对象的形式做为参数传进函数中。
[20-缓动动画修改多个样式.html]
var box = document.getElementById('box'); var btn = document.getElementById('btn'); // 封装一个函数,element 表示执行动画的元素 obj传的是一个对象,里面能够设置多个属性和值 function animate(element, obj) { clearInterval(element.timer); element.timer = setInterval(function() { // 遍历外部传进来的对象 for (k in obj) { //attr : 要作动画的样式 //target : 目标值 var attr = k; var target = obj[k]; // 获取元素开始时计算后的样式 var leader = getStyle(element, attr); leader = parseInt(leader) || 0; // 缓动动画函数原理 var step = (target - leader) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); leader += step; // 给元素设置以样式属性名为attr的值 // 这个封装的动画函数只能改值是px单位的样式 element.style[attr] = leader + "px"; if (leader == target) { clearInterval(element.timer); } } }, 15); } // 处理兼容性 function getStyle(element, attr) { if (window.getComputedStyle) { return window.getComputedStyle(element, null)[attr]; } else { return element.currentStyle[attr]; } } // 调用函数 设置了五个样式属性 btn.onclick = function() { animate(box, { width: 200, height: 200, left: 300, top: 300, // bprder-radius 应该转为驼峰命名法 而且值只能是100px的格式 不能是百分比 borderRadius: 100 }); }
效果图:
经过上面封装的函数咱们能够改变多个样式,可是效果图中咱们能够看到一个问题,就是当到达设定值后,点击按钮还会慢慢的抖动。缘由是修改多个样式的时候,全部的样式并不能都到同时达终点。
出现这个bug的缘由:在for循环中判断是否到达目标值,到达后就清除定时器,可是咱们同时修改了5个样式,可能有的样式到达目标值后就清楚定时器了,可是有的样式还没到达目标值,因此就出现了上面的
bug
。
解决方法:假设成立法
示例代码: [21-缓动动画修改多个样式-修复定时器bug.html]
function animate(element, obj) { clearInterval(element.timer); element.timer = setInterval(function() { // 1-假设都到达了终点 var flag = true; for (k in obj) { var attr = k; var target = obj[k]; var leader = getStyle(element, attr); leader = parseInt(leader) || 0; var step = (target - leader) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); leader += step; element.style[attr] = leader + "px"; // 2- 必需要等到全部的样式都到达终点才清除定时器 // 只要有一个样式没有到达设定值,说明假设失败 if (leader != target) { flag = false; } } // 全部的样式都到达终点后 清除定时器 if (flag) { clearInterval(element.timer); } }, 15); }
通过前面几小节的学习,咱们已经能够实现同时修改多个样式的缓动动画了。可是细心的小伙伴不知道有没有发现,目前只能设置跟px
有关系的样式,包括设置border-radiu
也不算完善。这是由于咱们缓动动画封装的时后,设置的element.style[attr] = leader + "px";
,因此只能实现跟px
有关的样式。
设置兼容其余属性的时候,要注意两点,第一获取的时候要进行判断,设置的时候也要进行判断
一、兼容opacity属性: [22-缓动动画修改多个样式-兼容opacity.html]
function animate(element, obj) { clearInterval(element.timer); element.timer = setInterval(function() { var flag = true; for (k in obj) { var attr = k; var target = obj[k]; // 判断得到的属性是否是“opacity”,是的话单独处理 var leader; // 得到当前值 if (attr === "opacity") { // 获取的时候是个小数,将它乘以100 运算时不会出现精度丢失 leader = getStyle(element, attr) * 100 || 1; } else { leader = getStyle(element, attr); leader = parseInt(leader) || 0; } var step = (target - leader) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); leader += step; // 赋值 // 判断是否是opacity属性 是的话 单独赋值 if (attr === "opacity") { // 由于开始的时候leader扩大了100倍 设置的时候 opacity只能是0-1 element.style[attr] = leader / 100; // opacity 还须要单独处理,由于IE678 不支持opacity element.style.filter = "alpha(opacity=" + leader + ")"; } else { element.style[attr] = leader + "px"; } if (leader != target) { flag = false; } } if (flag) { clearInterval(element.timer); } }, 15); } // 处理获取样式兼容性 function getStyle(element, attr) { if (window.getComputedStyle) { return window.getComputedStyle(element, null)[attr]; } else { return element.currentStyle[attr]; } } // 调用这个函数 btn.onclick = function() { animate(box, { width: 200, height: 200, left: 300, top: 300, // 这里是按照 0-100 设置不透明度的,由于小数计算的时候会出现精度丢失 opacity: 50 }); }
二、兼容zIndex属性: [23-缓动动画修改多个样式-兼容zIndex.html]
zIndex这个属性不须要缓动的执行改变层级,直接得到传进来的值设置便可
// 赋值 if (attr === "opacity") { element.style[attr] = leader / 100; element.style.filter = "alpha(opacity=" + leader + ")"; // 判断设置的时候是不是zIndex属性 } else if (attr === "zIndex") { element.style.zIndex= leader; } else { element.style[attr] = leader + "px"; }
示例代码: [24-缓动动画淡入淡出效果.html]
btn1.onclick = function() { animate(box, { opacity: 100 }) } btn2.onclick = function() { animate(box, { opacity: 0 }) }
效果图:
程序执行完毕,再次执行的函数。
示例代码: [25-缓动动画添加回调函数.html]
var box = document.getElementById('box'); var btn = document.getElementById('btn'); function animate(element, obj, fn) { clearInterval(element.timer); element.timer = setInterval(function() { var flag = true; for (k in obj) { var attr = k; var target = obj[k]; var leader = getStyle(element, attr); leader = parseInt(leader) || 0; var step = (target - leader) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); leader += step; element.style[attr] = leader + "px"; if (leader != target) { flag = false; } } if (flag) { clearInterval(element.timer); // 全部程序执行完毕了,如今能够执行回调函数了 // 只有传递了回调函数,才能执行,因此这里要判断一下 if (fn) { fn(); } /* fn&&fn(); */ } }, 15); } // 处理兼容性 function getStyle(element, attr) { if (window.getComputedStyle) { return window.getComputedStyle(element, null)[attr]; } else { return element.currentStyle[attr]; } } // 调用函数 btn.onclick = function() { animate(box, { left: 600 }, function() { animate(box, { top: 500, borderRadius: 50 }, function() { animate(box, { width: 400, borderRadius: 50 }); }); }); }
效果图:
直接看效果图:
效果如上图,当咱们鼠标通过某一项时,小方块会缓动移过去,当离开列表栏时,小方块会回到最初的位置。当点击某一项时小方块的初始位置就会停留在该项上。
示例代码: [26-筋斗云案例.html]
<!-- 样式部分 --> <style> body { padding: 0; margin: 0; background: #333; } #box { width: 800px; height: 34px; margin: 100px auto; background: orange; position: relative; } ul { padding: 0 50px; height: 34px; position: relative; } #box ul li { float: left; width: 100px; height: 34px; line-height: 34px; text-align: center; list-style: none; font-size: 18px; font-family: '方正'; color: #fff; cursor: pointer; } #over { position: absolute; top: -3px; left: 51px; width: 100px; height: 38px; background: orangered; } </style> <!-- html 部分 --> <div id='box'> <span id='over'></span> <ul id='nav'> <li>首页</li> <li>社区服务</li> <li>智慧超市</li> <li>便民</li> <li>圈子</li> <li>活动</li> <li>聚优惠</li> </ul> </div> <!-- js 部分 --> <script> var over = document.getElementById('over'); var nav = document.getElementById('nav'); var lis = nav.children; for (var i = 0; i < lis.length; i++) { lis[i].onmouseover = function() { // 鼠标通过时移动的距离就是它距离左边的距离 slowAnimate(over, this.offsetLeft); } // 设定默认位置,由于第一个选项距离左边为51px距离因此,默认值设置为51 var staticLeft = 51; lis[i].onmouseout = function() { // 鼠标离开的时候,要让它回到默认位置 slowAnimate(over, staticLeft); } lis[i].onclick = function() { // 当点击某一选项的时候,将默认位置设置为此时的位置 staticLeft = this.offsetLeft; } } // 缓动动画 function slowAnimate(element, target, num) { clearInterval(element.timer); element.timer = setInterval(function() { var leader = element.offsetLeft; // num 不传的话,默认是10 var step = (target - leader) / (num || 10); step = step > 0 ? Math.ceil(step) : Math.floor(step); leader += step; element.style.left = leader + 'px'; if (leader == target) { clearInterval(element.timer); } }, 15); } </script>
在网页中常常会出现广告,咱们举个例子让关闭广告的时候有一个动画效果。
实现原理:
0
,因此会出现一个向下的效果0
,因此出现一个向右的效果示例代码: [27-右下角关闭广告案例.html]
<!-- 样式部分 --> <style> #box { width: 213px; position: fixed; bottom: 0; right: 0; overflow: hidden; } #close { position: absolute; top: 0; right: 0; width: 30px; height: 30px; cursor: pointer; color: #FFFFFF; text-align: center; } .img { display: block; width: 212px; z-index: 99; } </style> <!-- html 部分 --> <div id="box"> <div id="hd"> <span id="close"> x </span> <img src="../image/关闭广告/banna_up.png" class="img" alt="" /> </div> <div id="bt"> <img src="../image/关闭广告/banner_down.png" class="img" alt="" /> </div> </div> <!-- js 部分 --> <script src="../js/slow-animate-styles.js"></script> <script> var close = document.getElementById('close'); var box = document.getElementById('box'); var bt = document.getElementById('bt'); close.onclick = function() { slowAnimateStyles(bt, { height: 0 }, function() { slowAnimateStyles(box, { width: 0 }); }); } </script>
效果图:
手风琴效果在网页中用的也特别的多,下面咱们会介绍两种实现的方法,固然我的比较偏好第二种。
一、浮动版手风琴
实现原理:
ul,li
进行布局,li
左浮动,而且设置等分的宽度;li
注册鼠标通过事件,当鼠标通过的时候利用排他原理,将全部的li
宽度设置成最小宽度,将当前通过的li
宽度设置一个最大宽度;li
再恢复到等分的宽度。示例代码: [28-手风琴-浮动版.html]
<!-- 样式部分 --> <style> * { margin: 0; padding: 0; list-style: none; } #box { width: 900px; height: 441px; margin: 100px auto; overflow: hidden; border-radius: 30px; } ul { /* ul的宽要比外面的盒子大一点,不然在添加动画效果的时候,最后一个li会出现闪动 */ width: 120%; height: 100%; overflow: hidden; } li { width: 180px; height: 100%; float: left; } </style> <!-- html 部分 --> <div id="box"> <ul> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> </div> <!-- js 部分 --> <script src="../js/slow-animate-styles.js"></script> <script> var box = document.getElementById('box'); var lis = box.getElementsByTagName("li"); for (var i = 0; i < lis.length; i++) { // 动态建立img标签 var img = document.createElement("img"); img.src = "../image/手风琴/" + (i + 1) + ".png"; lis[i].appendChild(img); // 给全部li注册鼠标通过事件,让当前的li宽度变成 500,其他的li宽度变成100 lis[i].onmouseover = function() { for (var i = 0; i < lis.length; i++) { // 先让全部的li宽度变成100 slowAnimateStyles(lis[i], { width: 100 }); // 鼠标当前通过的宽度为500 slowAnimateStyles(this, { width: 500 }) } }; // 当鼠标离开的时候,因此的li 宽度恢复到180px lis[i].onmouseout = function() { for (var i = 0; i < lis.length; i++) { slowAnimateStyles(lis[i], { width: 180 }) } } } </script>
效果图:
二、定位版手风琴
实现原理:
ul,li
结构,li
设置宽高,与图片大小一致,设置绝对定li
添加背景图片,由于li
绝对定位的缘由,此时全部的li
都叠在一块儿li
设置left
值(left*i
),这时候li
就会依次排开overflow-hidden
属性,将多余的隐藏掉li
注册鼠标鼠标通过事件,而后根据下面推算出的规律(当前鼠标通过的索引index
,他以前包括他本身的left
值都是,设定的最小值乘以对应的索引。而他后面的会将设定的最小值乘以对应的索引后再加上450
,这里的450
不是一个固定值,根据规律找出来的)进行判断,设置各自的left
值;大盒子没有overflow-hidden
的时候:
画个图,理解一下:
找规律:
结合上面的图片,咱们能够找到一个规律
当鼠标在第1个li上的时候,li下标index为0:
当鼠标在第2个li上的时候,li下标index为1:
当鼠标在第3个li上的时候,li下标index为2:
看出规律了吗?
<=
鼠标悬停的的下标上的时候left
值 是50*i
>
鼠标悬停的的下标上的时候left
值 是50*i + ,450
(450不是固定的值,是通过计算出来的)示例代码: 29-手风琴-定位版.html]
<!-- 样式部分 --> <style> * { margin: 0; padding: 0; list-style: none; } #box { width: 700px; height: 440px; margin: 100px auto; position: relative; overflow: hidden; box-sizing: border-box; border-radius: 30px; } li { width: 700px; height: 440px; position: absolute; /* background: yellow; */ } </style> <!-- html 部分 --> <div id="box"> <ul> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> </div> <!-- js 部分 --> <script src="../js/slow-animate-styles.js"></script> <script> var box = document.getElementById('box'); var lis = box.getElementsByTagName('li'); for (var i = 0; i < lis.length; i++) { lis[i].index = i; // 动态添加li的背景图片 由于i下标从0开始,可是图片序号是从1开始 因此jia1 lis[i].style.backgroundImage = "url(../image/手风琴/" + (i + 1) + ".png)"; // 如今都叠在一块儿,设置left 让他们分开来 700/5 ==> 140px lis[i].style.left = 140 * i + "px"; // 注册鼠标通过事件,让当前的显示宽度为500,其他的为50 lis[i].onmouseover = function() { for (var i = 0; i < lis.length; i++) { // 判断当i小于等于当前鼠标停留的下标的时候,给li的left设置 50*i if (i <= this.index) { slowAnimateStyles(lis[i], { left: 50 * i }); // 当i大于当前鼠标停留的索引的时候,给后边的li的left设置 50*i + 450 } else { slowAnimateStyles(lis[i], { left: 50 * i + 450 }); } } } // 注册鼠标离开事件,让全部的li都恢复到最初的样式 lis[i].onmouseout = function() { for (var i = 0; i < lis.length; i++) { slowAnimateStyles(lis[i], { left: 140 * i }); } } } </script>
效果图:
旋转木马也叫旋转轮播图,在效果上它就是旋转版的轮播图,可是在实现原理上却一点一不同
旋转木马原理:
ul
、li
方式将图片包裹在li
里,而且对每一个li
的大小、层级、不透明度以及定位的位置设置好datas
中pop
、unshift
、shift
、push
datas
里的最后一项利用pop
删除掉,而且返回这个删除的数据,再将这个数据unshift
到数组的最前面。从新遍历数组,执行一遍动画datas
里的最前面一项利用shift
删除掉,而且返回这个删除的数据,再将这个数据push
到数组的最后面。从新遍历数组,执行一遍动画示例代码: [30-旋转木马轮播图案例.html]
<!-- 样式部分 --> <style> * { margin: 0; padding: 0; list-style: none; } body { background: #666; } .wrap { width: 1200px; margin: 200px auto; } .slide { height: 340px; position: relative; } .slide li { position: absolute; left: 300px; top: 0; } img { width: 100%; } .arrow { opacity: 0; position: relative; z-index: 99; top: 50%; } .arrow #left, .arrow #right { width: 40px; height: 90px; position: absolute; top: 50%; margin-top: -45px; background: url(../image/旋转木马/left.png); background-size: cover; z-index: 99; } .arrow #right { right: 0; background: url(../image/旋转木马/right.png); background-size: cover; } </style> <!-- html 部分 --> <div class="wrap" id="wrap"> <div class="slide" id="slide"> <ul> <li><img src="../image/1.jpg" alt=""></li> <li><img src="../image/2.jpg" alt=""></li> <li><img src="../image/3.jpg" alt=""></li> <li><img src="../image/4.jpg" alt=""></li> <li><img src="../image/5.jpg" alt=""></li> </ul> <div class="arrow" id="arrow"> <a href="javascript:;"><span id="left"></span></a> <a href="javascript:;"><span id="right"></span></a> </div> </div> </div> <!-- js 部分 --> <script src="../js/slow-animate-styles.js"> </script> <script> // 将其他四张位置与透明度等信息,存放在一个数组中 var datas = [{ "width": 300, "top": -20, "left": 150, "opacity": 20, "zIndex": 2 }, //0 { "width": 500, "top": 30, "left": 50, "opacity": 80, "zIndex": 3 }, //1 { "width": 600, "top": 100, "left": 300, "opacity": 100, "zIndex": 4 }, //2 { "width": 500, "top": 30, "left": 650, "opacity": 80, "zIndex": 3 }, //3 { "width": 300, "top": -20, "left": 750, "opacity": 20, "zIndex": 2 } //4 ]; var slide = document.getElementById('slide'); var lis = slide.getElementsByTagName('li'); var arrow = document.getElementById('arrow'); var left = document.getElementById('left'); var right = document.getElementById('right'); // 定义一个节流阀 var flag = true; // 一开始页面刷新的时候,将datas里的数据 动态添加进去 for (var i = 0; i < lis.length; i++) { slowAnimateStyles(lis[i], datas[i]); }; // 鼠标通过的时候 箭头显示 slide.onmouseover = function() { slowAnimateStyles(arrow, { opacity: 100 }) }; // 鼠标离开的时候 箭头隐藏 slide.onmouseout = function() { slowAnimateStyles(arrow, { opacity: 0 }) }; // 点击右箭头的时候 // 利用数组的pop 和 unshift方法对数组datas进行操做 // pop 会删除数组的最后一项,而且返回这一项。 unshift 会在数组的最前添加 right.onclick = function() { // 只有节流阀为true的时候 点击才会执行里面的代码 if (flag) { // 电击后一进来就将节流阀关上,再次点击的时候就不会进来 flag = false; datas.unshift(datas.pop()); for (var i = 0; i < lis.length; i++) { // 点击一次就要动画渲染一次,datas[i] 实际上是一个对象 /* { "width": 300, "top": -20, "left": 150, "opacity": 20, "zIndex": 2 } */ slowAnimateStyles(lis[i], datas[i], function() { // 当动画执行完,也就是回调函数触发的时候,再将节流阀打开,这样就能够继续点击了 flag = true; }); } } } // 点击左箭头 // 利用数组的 shift 和 push方法对数组datas进行操做 // shift 会删除数组的第一项,而且返回这一项。 push 会在数组的最后添加 left.onclick = function() { if (flag) { flag = false; datas.push(datas.shift()); for (var i = 0; i < lis.length; i++) { slowAnimateStyles(lis[i], datas[i], function() { flag = true; }); } } } </script>
效果图: