Javascript学习记录——原生JS实现旋转木马特效
昨天学习到了JS特效部分,然后老师讲了旋转木马特效的实现,如上图。不过只是讲了通过点击箭头实现图片的切换,对于点击图片本身以及二者联动却是没有讲解。
本着一颗追求完美的心,今天花费了一个中午终于将整个功能全部完善(死了太多脑细胞~~)。
接下来直接进入主题哈~(主要讲解JS,所以对其中的HTML及CSS不做详细说明。)
首先是HTML代码
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>旋转木马轮播图</title> <link rel="stylesheet" href="css/css.css"/> </head> <body> <div class="wrap" id="wrap"> <div class="slide" id="slide"> <ul> <li><a href="#"><img src="data:images/slidepic1.jpg" alt=""/></a></li> <li><a href="#"><img src="data:images/slidepic2.jpg" alt=""/></a></li> <li><a href="#"><img src="data:images/slidepic3.jpg" alt=""/></a></li> <li><a href="#"><img src="data:images/slidepic4.jpg" alt=""/></a></li> <li><a href="#"><img src="data:images/slidepic5.jpg" alt=""/></a></li> </ul> <div class="arrow" id="arrow"> <a href="javascript:;" class="prev" id="arrLeft"></a> <a href="javascript:;" class="next" id="arrRight"></a> </div> </div> </div> </body> </html>
以下为CSS代码:
blockquote, body, button, dd, dl, dt, fieldset, form, h1, h2, h3, h4, h5, h6, hr, input, legend, li, ol, p, pre, td, textarea, th, ul { margin:; padding: 0 } body, button, input, select, textarea { font: 12px/1.5 "Microsoft YaHei", "微软雅黑", SimSun, "宋体", sans-serif; color: #666; } ol, ul { list-style: none } a { text-decoration: none } fieldset, img { border:; vertical-align: top; } a, input, button, select, textarea { outline: none; } /*以上为简单的初始化*/ a, button { cursor: pointer; } .wrap { width: 1200px; margin: 100px auto; } .slide { height: 500px; position: relative; } .slide li { position: absolute; left: 200px; top:; } .slide li img { width: 100%; } .arrow { opacity:; position: absolute; top: 200px; z-index:; } .arrow .next{ left: 1120px; } .prev, .next { width: 76px; height: 112px; position: absolute; top: 50%; margin-top: -56px; background: url(../images/prev.png) no-repeat; z-index:; } .next { right:; background-image: url(../images/next.png);
以下为JS代码:先说明一下整体的思路
1、设置鼠标移入移出事件,显示图片中的左右两个箭头
2、设置左右两个箭头的点击事件,通过点击箭头,实现配置单中的样式切换(因为获取图片所在的li是一个伪数组,无法使用数组的方法,所以图片的轮播实现主要是通过对配置单内元素索引的改变完成的。)
3、设置点击li(也就是图片,后面统一写为li)标签实现点击的li出现在界面最前端。
4、实现点击箭头后,点击li的联动,也就是无论点击箭头多少次,再次点击li后,也能将当前点击的li显示在界面最前端。
5、实现点击li后,点击箭头的联动,也就是无论点击li后当前界面最前端的li是哪一个,再次点击箭头后,都能按照点击箭头的规则切换到当前li的下一个或上一个li。
是不是有点啰嗦啊 0...0
<script>
(function(){//今天偶尔看到一篇问文章,其中说道用自调用函数封装自己的JS代码可以防止环境污染哈~好像还有其他很好的功能,还没有详细了解,这里就拿出来爽一下~ var config = [ { width: 400, top: 20, left: 50, opacity: 0.2, zIndex: 2 }, { width: 600, top: 70, left: 0, opacity: 0.8, zIndex: 3 }, { width: 800, top: 100, left: 200, opacity: 1, zIndex: 4 }, { width: 600, top: 70, left: 600, opacity: 0.8, zIndex: 3 }, { width: 400, top: 20, left: 750, opacity: 0.2, zIndex: 2 } ];//config为一个配置单 规定了每张图片的大小位置层级透明度 //获取元素 var wrap = document.getElementById('wrap') var slide = document.getElementById('slide') var ul = slide.children[0] var lis = ul.children var arrow = document.getElementById('arrow') var arrLeft = document.getElementById('arrLeft') var arrRight = document.getElementById('arrRight') //4.3 因为要控制图片显示的频率,因此要等到每次图片正常切换完成才进行下一次图片切换,假设初始时图片切换完成 flag == true var flag = true, count = 2, cFlag = false //7.92 这里设置cFlag初始值为false /** * 缓动改变样式的函数,先封装这个函数,后面进行配置单内的样式添加只需要调用这个函数就可以了。 * @param tag 要改变的元素 * @param json 一个对象,里面以属性保存要修改的样式 * @param fn 传入函数,可以在第一次调用执行后,再执行传入的函数体内容 */ function perfectAnimate(tag, json, fn) { clearInterval(tag.timer)//首先清除定时器 tag.timer = setInterval(function () {//新建一个setInterval,设置周期时间为18ms,这个数字不固定~ var flag = true //这里运用了假设成立法 for (var k in json) { //遍历传入的对象 if (k == 'opacity') { //判断对象中保存的样式,如果为opacity,单独设置 var leader = getStyle(tag, k) * 100 //这里获取opacity的初始值。这里使用的是下面获取样式的兼容函数。
//乘100是因为JS小数计算存在精度问题。所以这里在下将其扩大100倍进行使用。 var target = json[k] * 100 //这里取出opacity的目标值,也就是对象中的样式属性值 var step = (target - leader) / 10; //这里用目标值减去初始值除以10达到缓动的目的(变速改变) step = step > 0 ? Math.ceil(step) : Math.floor(step);//这里也可以不使用这个判断,对step向上或向下保证最后的时候每次都能至少走1 leader = leader + step; //初始值加上每次增加或减少的值 tag.style[k] = leader / 100; //将值设置给opacity属性,当然别忘了把100除回来~ } else if (k == 'zIndex') { tag.style[k] = json[k] //如果为zIndex 这时候就直接设置给样式就行了。 } else { var leader = parseInt(getStyle(tag, k)) || 0 //当样式属性值为带单位的时候,这时候要进行一个取整去掉单位,同时为了防止没有初始值而默认为auto,使用一个短路操作 var target = json[k] var step = (target - leader) / 10 step = step > 0 ? Math.ceil(step) : Math.floor(step) leader = leader + step tag.style[k] = leader + 'px' } if (target != leader) { flag = false //这里只要有一个没有样式没有设置完成,假设便不成立,便不执行下面的清除 } } if (flag) { //假设所有属性都设置完成,便清除定时器,节约空间 clearInterval(tag.timer) // if ("function" == typeof fn) { // fn() // } fn && fn();//清除定时器后,可能会有需要的功能要在以上执行完成后执行,这里使用一个回调函数,
//同样使用短路操作,防止没有传函数而报错。上面注释的与这个功能一样,只是更严谨,这个更简洁 } }, 18) } /** * 获取多个样式的方法的兼容性。current是IE自己的,不支持getComputedStyle * @param tag 是标签名 * @param attr 是具体的某个样式的属性 * @returns {*} 返回的是这个样式的属性值 */ function getStyle(tag, attr) { if (tag.currentStyle) { return tag.currentStyle[attr]; } else { return getComputedStyle(tag, null)[attr]; } } //以上准备工作做完,然后可以开始我们代码代码的书写了。
//哎呀,好困呀~~还好后面的内容在我中午写的时候已经做好注释了,省了不少时间哇,哈哈哈哈....
//建议以序号顺序进行阅读哈,虽然自我感觉挺详细的,但是可能存在某些表述不准确的地方,望谅解~毕竟这才是我的第二篇博客啦...
/** * 1 封装函数,将config中的样式一一对应设置给li标签,因为后面会多次调用它 */ function change() { for (var i = 0; i < config.length; i++) { perfectAnimate(lis[i], config[i], function () { flag = true//4.6 这里在perfectAnimate函数中传入函数,赋值flag为true,因为这时候图片切换已经完成,可以进行下一次切换了。
}) } }
//2 最开始的默认分布(也就是上图那个效果~),直接调用函数
change() //3 设置移入移出事件,显示与隐藏箭头
wrap.onmouseover = function () { perfectAnimate(arrow, {'opacity': 1}) } wrap.onmouseout = function () { perfectAnimate(arrow, {'opacity': 0}) } /** * */ function clearChangeConfig2() { if (cFlag) { //7.93 因为最开始点击箭头时,没有进行li的点击切换,不需要进行联动,只有点击过li后,再点击箭头才执行,可以 // 使用cFlag作为判断条件 cFlag = false //7.91 这里被调用是需要执行changeConfig1(this.index)里面的if判断,所以首先设置cFlag为false for (var i = 0; i < lis.length; i++) { //7.4 因为点击li后图片进行切换后,config中的元素又回到初始位置,与设置给li的并不相同,这时就需要 // 将点击li时最后执行的changeConfig2(this.index),再退回到changeConfig1(this.index),要做到上一 // 步,就需要找到当前点击的li的索引,因为当前点击的li肯定是设置有属性zIndex=4,并且其index属性保存了 // 其索引值,所以通过这就可以找到需要的索引了。 if (lis[i].style.zIndex == 4) { changeConfig1(lis[i].index)//7.5 找到索引后直接将config中元素的位置退回到changeConfig1(this.index)
} } } } function pushCount() { if (count <= config.length && count > 0) { count-- } else { count = 4 } } function unshiftCount() { if (count < config.length && count >= 0) { count++ } else { count = 0 } } //4 添加右箭头点击事件
arrRight.onclick = function () { if (flag) {//4.4 如果flag为true,即4.3假设成立,便执行下面的代码 flag = false//4.5 给flag设置为false,使假设不成立,这时候只要没有改变flag值,点击事件源将不在执行这里的代码,不过此次下面代码依旧会执行 clearChangeConfig2()//7.3 这里调用是为了点击li后,实现箭头的联动,具体看7.4 config.push(config.shift())//4.1 点击后将第一个样式剪切到最后一个 change()//4.2 通过调用函数,将新生成的config元素一一对应设置给li标签
//7.0 点击箭头后,实现与li点击联动,每次点击右箭头count值都会自减一次,count初始值为2.小于0后直接赋值为4
//count的值对应的是每次进行切换后,zIndex值为4的元素在config中的索引值,并以此为初始值(取代6.5设置的2)——界面最前端的配置属性,使得点击li时正常切换
pushCount() } } //5 添加左箭头点击事件
arrLeft.onclick = function () { if (flag) { flag = false clearChangeConfig2() config.unshift(config.pop())//5.1 点击后将最后一个样式剪切到第一个 change() //5.2 通过调用函数,将新生成的config元素一一对应设置给li标签 unshiftCount()//7.1 将箭头点击与li点击联动,每次点击左箭头count值都会自增一次,count初始值为2.大于4后直接赋值为0 } } /** * 6.3 根据当前点击的li的索引值,给li设置config内元素中的属性 * @param i 当前点击li的索引值 */ function changeConfig1(i) { //6.5 未设置联动时,count位置应该是数字2,即最开始时zIndex值为4的config元素对应的索引,改变的中心思想为:zIndex中值为4的config元素(界面最前端的配置属性)
// 总是设置给当前的点击的li,保持二者索引一致(count先不管) //6.6 然后进行判断,如果当前li的索引值小于等于2 //7.2 这时将count作为条件依据,等同于以zIndex值为4的元素的索引为依据 if (i <= count) { for (var i = i; i < count; i++) { config.push(config.shift())//6.7 那么根据其索引值进行0位config元素的剪切,直到zIndex值为4的config元素对应的索引与当前点击的li的索引一致 if (cFlag == false) {//7.8 又因为点击li时,config元素与li进行对应设置后,又会回到初始位置,不会影响到count的变化 //所以点击li时调用这个函数不能执行这个if判断,这里再次使用假设成立法,假设cFlag为false时执行if判断成立 pushCount()//7.6 因为将config中元素的位置改为正常的后,zIndex=4的元素的索引又会发生变化,所以这时count也要跟着变化 i--//7.7 这里的count为--,所以i值也要--才能保证count自减的次数与循环执行次数一致(即与config元素剪切的次数一致,即保证count的值总是配置单中zIndex=4的元素的索引) } } } else { for (var i = i; i > count; i--) { config.unshift(config.pop())//6.8 如果大于2,那么根据其索引值进行索引为4的config元素的剪切,直到zIndex值为4的config元素对应的索引与当前点击的li的索引一致 if (cFlag == false) { unshiftCount() i++ } } } } function changeConfig2(i) { if (i <= count) { for (var i = i; i < count; i++) { config.unshift(config.pop()) if (cFlag == false) { pushCount() } } } else { for (var i = i; i > count; i--) { config.push(config.shift()) if (cFlag == false) { unshiftCount() } } } } //6 遍历lis,给li设置点击事件
for (var i = 0; i < lis.length; i++) { lis[i].index = i//6.4 以lis[i]的自定义属性index保存其索引值 lis[i].onclick = function () {//6.1 添加事件 cFlag = true //7.9 点击li时执行changeConfig1(this.index)之前将cFlag赋值true,即不执行它里面的if判断 changeConfig1(this.index)//6.2 点击li后将zIndex值为4的config元素添加给当前点击的li,其他元素依次挪动。 change()//6.9通过调用函数,将修改后的config内的元素属性一一对应设置给li changeConfig2(this.index)//6.91 在第6.2步中,zIndex值为4config元素进行过剪切可能已经不在索引为2的位置了,这时后我们再进行与6.2步中相反的操作 // 将config中的元素位置回归到初始状态,但是并不设置给li. } }
}())
</script>
最后本着负责的态度,还是认真对着上面的文字检查了20分钟,确保在自己水平内将问题讲清楚——可是、好像还是不够太具体化...
看来只能等以后的理解更加透彻后,再对本文进行修改了。
——BY:骑士与魔王(我微博也是这个名字哈,里面还有自己之前玩微博时写的图文小说,《骑士与魔王》,可惜太监啦,哈哈哈哈)
Javascript学习记录——原生JS实现旋转木马特效的更多相关文章
- JavaScript学习记录三
title: JavaScript学习记录三 toc: true date: 2018-09-14 23:51:22 --<JavaScript高级程序设计(第2版)>学习笔记 要多查阅M ...
- JavaScript学习记录二
title: JavaScript学习记录二 toc: true date: 2018-09-13 10:14:53 --<JavaScript高级程序设计(第2版)>学习笔记 要多查阅M ...
- JavaScript学习记录四
title: JavaScript学习记录四 toc: true date: 2018-09-16 20:31:22 --<JavaScript高级程序设计(第2版)>学习笔记 要多查阅M ...
- JavaScript学习记录一
title: JavaScript学习记录一 toc: true date: 2018-09-11 18:26:52 --<JavaScript高级程序设计(第2版)>学习笔记 要多查阅M ...
- 原生js实现架子鼓特效
这是代码完成的效果,按下abcd会出现对应的架子鼓音乐的效果. 简单的介绍下代码思路,html和css部分就不多说了. 重要的是js部分. 大致是这样的, 首先获取到所有的按钮为一个数组,然后遍历整个 ...
- 原生JS实现旋转木马轮播图特效
大概是这个样子: 首先来简单布局一下(emm...随便弄一下吧,反正主要是用js来整的) <!DOCTYPE html> <html lang="en"> ...
- 诶西,JavaScript学习记录。。。。。。
由于大学课程缘故,老师巨爱叫人问问题,还记分呢,随便记录一下Js的学习情况,以后复习什么的也比较方便吧...... 开始咯,就按照C语言学习那样的方法来吧! ===================== ...
- 原生JS实现"旋转木马"效果的图片轮播插件
一.写在最前面 最近都忙一些杂七杂八的事情,复习软考.研读经典...好像都好久没写过博客了... 我自己写过三个图片轮播,一个是简单的原生JS实现的,没有什么动画效果的,一个是结合JQuery实现的, ...
- JavaScript学习记录总结(四)——js函数的特殊性
<script type="text/javascript"> //当局部变量与全局变量 重名的时候 var v="全局变量";//定义全局变 ...
随机推荐
- 普林斯顿算法课第五周作业_KdTree
作业地址:http://coursera.cs.princeton.edu/algs4/assignments/kdtree.html 作业难点: 1.如何构建KdTree,使用什么样的数据结构? 根 ...
- 使用MonkeyTest对Android客户端进展压力测试
Monkey是Android中的一个命令行工具,可以运行在模拟器里或实际设备中.它向系统发送伪随机的用户事件流(如按键输入.触摸屏输入.手势输入等),实现对正在开发的应用程序进行压力测试. 先来看一条 ...
- 页面制作之HTML
标签 常用属性 id class style title - <a href ="/" title="收藏">收藏</a>(用于hove ...
- Jstack Jmap jstat
jstack jmap jstat 代码,这里以这个为例怎样使用jstack诊断Java应用程序故障 public class DeadLock { public static void main(S ...
- fragment 重叠问题
项目中用到了Android Fragment 在程序异常的时候 fragment 点击会造成fragment 重叠 在fragmentActivity中加入一下方法 @Override public ...
- Visual Studio 2015 Update 2正式版下载地址
转载自:王彬的博客 地址:http://blog.sina.com.cn/s/blog_55f899fb0102wcwg.html Visual Studio Professional 2015(带 ...
- 在Andoid开发中使用MVP模式来解耦,增加可测试性
by Jeff Angelini posted on 7/20/2011 2:35:00 PM 将应用程序UI的表现从Ui的逻辑中分离是一个好的想法.这种分离减少了代码耦合,代码更加干净, 甚至可以有 ...
- 关于MySQL 的LEFT JOIN ON的问题
今天在查询视图时,遇到了一个问题. 因为mysq不能嵌套select的子查询.所以我把子查询建成了视图b,主查询通过left join on关联视图b ,形成视图a. 由于视图b中也有left joi ...
- Win32 OpenProcess打开进程失败,返回5无权限操作
Win32 OpenProcess打开进程失败,返回5无权限操作,相信你会碰到这样的事,在IDE中可以,单独却不可以了,其实这时就需要提权了,否则是无法打开的,OpenProcess提权至Debug即 ...
- mysql外键添加error1215
在mysql创建表外键的过程中,由于操作不当,会提示cannot add foreign key constraint的错误. 造成此错误可能的原因如下: 1.数据类型不匹配,外键与其相关联的键必须数 ...