昨天学习到了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实现旋转木马特效的更多相关文章

  1. JavaScript学习记录三

    title: JavaScript学习记录三 toc: true date: 2018-09-14 23:51:22 --<JavaScript高级程序设计(第2版)>学习笔记 要多查阅M ...

  2. JavaScript学习记录二

    title: JavaScript学习记录二 toc: true date: 2018-09-13 10:14:53 --<JavaScript高级程序设计(第2版)>学习笔记 要多查阅M ...

  3. JavaScript学习记录四

    title: JavaScript学习记录四 toc: true date: 2018-09-16 20:31:22 --<JavaScript高级程序设计(第2版)>学习笔记 要多查阅M ...

  4. JavaScript学习记录一

    title: JavaScript学习记录一 toc: true date: 2018-09-11 18:26:52 --<JavaScript高级程序设计(第2版)>学习笔记 要多查阅M ...

  5. 原生js实现架子鼓特效

    这是代码完成的效果,按下abcd会出现对应的架子鼓音乐的效果. 简单的介绍下代码思路,html和css部分就不多说了. 重要的是js部分. 大致是这样的, 首先获取到所有的按钮为一个数组,然后遍历整个 ...

  6. 原生JS实现旋转木马轮播图特效

    大概是这个样子: 首先来简单布局一下(emm...随便弄一下吧,反正主要是用js来整的) <!DOCTYPE html> <html lang="en"> ...

  7. 诶西,JavaScript学习记录。。。。。。

    由于大学课程缘故,老师巨爱叫人问问题,还记分呢,随便记录一下Js的学习情况,以后复习什么的也比较方便吧...... 开始咯,就按照C语言学习那样的方法来吧! ===================== ...

  8. 原生JS实现"旋转木马"效果的图片轮播插件

    一.写在最前面 最近都忙一些杂七杂八的事情,复习软考.研读经典...好像都好久没写过博客了... 我自己写过三个图片轮播,一个是简单的原生JS实现的,没有什么动画效果的,一个是结合JQuery实现的, ...

  9. JavaScript学习记录总结(四)——js函数的特殊性

    <script type="text/javascript">  //当局部变量与全局变量 重名的时候   var v="全局变量";//定义全局变 ...

随机推荐

  1. 【HTTP】模拟form提交表单(转)

    第一种:WebClient string postString = "arg1=a&arg2=b";//这里即为传递的参数,可以用工具抓包分析,也可以自己分析,主要是for ...

  2. BZOJ 2342 & manachar+最优性剪枝

    题意: 求最长回文串,串的两边都是回文串. Solution: manachar预处理然后暴力找... Code: #include <iostream> #include <cst ...

  3. xcode 一般插件

    插件编写 xcode的插件不算多,找遍了网络也就大猫小猫而三只.不过虽然不多,但是大部分的插件都非常有用.以下5歀插件是我几台机器上都安装了并且经常使用的. 1. MiniXcode MiniXcod ...

  4. JS区分移动端和PC

    var ua = navigator.userAgent.toLowerCase(); if (ua.match(/MicroMessenger/i) == "micromessenger& ...

  5. AFNetWorking设置HTTPRequestHeaders的坑

    今天在项目中要封装一个请求头但是用如下方法总是失败: 求其原因不知道: 于是乎改用了属性对象后居然成功了..: // //  RequestManager.m //  获取天气demo // //  ...

  6. VMware创建Linux虚拟机并安装CentOS(一)

    在VMware中新建虚拟机,在新建虚拟机向导中,选择“自定义(高级)”选项,鼠标单击“继续”按钮 选择VMware的版本workstation9.0(VMware版本对硬盘.内存.cpu等硬件的支持大 ...

  7. angluar去掉url中#

    众所周知,angular项目中路由机制会在地址栏加一个#来实现各个页面的切换,虽然url中有个#号也无伤大雅,但每次看到多一个这个东西总是不舒服(我不是强迫证啊),趁着项目间隙还是决定把它去掉. 去谷 ...

  8. 在update语句中使用子查询

    在update 中的 where 子句中使用子查询: UPDATE mg_page_log as a  SET  page_num=1 WHERE id in( SELECT id  from mg_ ...

  9. [转]android:动态创建多个按钮 及 批量设置监听

    之前投机取巧,先创建好多个按钮,再根据需要的数量进行部分隐藏,不过还是逃不过呀. 这样根本无法批量地 findId,批量地 设置监听. 所以今天还是认认真真地研究回“动态创建按钮”,终于,通过不断尝试 ...

  10. SQL执行效率1

    第一种方法:使用insert into 插入,代码如下: ? 1 2 3 4 5 6 7 $params = array('value'=>'50′); set_time_limit(0); e ...