第九节 JS运动应用
Posted han-bky
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第九节 JS运动应用相关的知识,希望对你有一定的参考价值。
多物体运动框架
多个物体同时运动
例子:多个Div,鼠标移入变宽
单定时器,存在问题
每个Div一个定时器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>多个div变宽</title> <style> div{ width: 100px; height: 50px; background: red; margin: 10px; } /*鼠标移入时宽度变宽;鼠标移除,恢复原状*/ </style> <script> // window.onload = function () { // var aDiv = document.getElementsByTagName(‘div‘); // for (var i=0; i<aDiv.length; i++){ // aDiv[i].onmouseover = function(){ // startMove(this, 400) // }; // aDiv[i].onmouseout = function(){ // startMove(this, 100) // }; // } // }; // // var timer = null; // function startMove(obj, iTarget){ // clearInterval(timer); // timer = setInterval(function () { // var speed = (iTarget - obj.offsetWidth)/6; // speed = speed>0?Math.ceil(speed):Math.floor(speed); // if (obj.offsetWidth==iTarget) { // clearInterval(timer); // } else { // obj.style.width = obj.offsetWidth+speed+‘px‘; // } // }, 30); // } //问题是,当我们把鼠标移入一个div,并快速移出,然后快速移入下一个div时,鼠标移入的第一个div有可能不能恢复原状, //其实问题的根源就是 整个程序就只有一个“定时器”,当第一个div在动的时候,还没有完全恢复,第二个div的定时器已经把 // 上一个的定时器覆盖掉,所以出现这种情况,解决办法如下: window.onload = function () { var aDiv = document.getElementsByTagName(‘div‘); for (var i=0; i<aDiv.length; i++){ aDiv[i].timer = null; //自定义属性,给每个div都加一个定时器 aDiv[i].onmouseover = function(){ startMove(this, 400) }; aDiv[i].onmouseout = function(){ startMove(this, 100) }; } }; // var timer = null; function startMove(obj, iTarget){ clearInterval(obj.timer); //关闭相应div的定时器 obj.timer = setInterval(function () { //开启相应div的定时器 var speed = (iTarget - obj.offsetWidth)/6; speed = speed>0?Math.ceil(speed):Math.floor(speed); if (obj.offsetWidth==iTarget) { clearInterval(obj.timer); //关闭相应div的定时器 } else { obj.style.width = obj.offsetWidth+speed+‘px‘; } }, 30); } </script> </head> <body> <div></div> <div></div> <div></div> </body> </html>
多物体运动框架
定时器作为物体的属性
参数传递:物体、目标值
例子:多个Div淡出淡入
所有东西都不能共用
属性与运动对象:速度、其他属性值(如透明度)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>多个div淡入淡出</title> <style> div{ width: 200px; height: 200px; margin: 20px; float: left; background: red; filter: alpha(opacity: 30); opacity: 0.3; } </style> <script> window.onload=function () { var aDiv = document.getElementsByTagName(‘div‘); for (var i=0; i<aDiv.length;i++){ aDiv[i].alpha = 30; //把每个div的alpha分开 aDiv[i].onmouseover = function () { startMove(this, 100); }; aDiv[i].onmouseout = function (){ startMove(this, 30); }; } }; // var alpha = 30; //虽然把alpha分开了不同的div,但是任然存在鼠标快速由一个div移入到另一个div时,透明度变化较慢的情况 // 所以我们的解决办法是,把每个div的alpha也分开, function startMove(obj, iTarget) { clearInterval(obj.timer); obj.timer = setInterval(function () { var speed = (iTarget-obj.alpha)/6; speed = speed>0?Math.ceil(speed):Math.floor(speed); if (obj.alpha==iTarget) { clearInterval(obj.timer); } else { obj.alpha+=speed; obj.style.filter = ‘alpha(opacity: ‘+obj.alpha+‘)‘; obj.style.opacity = obj.alpha/100; } }, 30); } </script> </head> <body> <div></div> <div></div> <div></div> <div></div> </body> </html>
任意值的运动框架
offset属性的Bug
有边框的Div变宽
用currentSty代替offset
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>a_bug_of_offset</title> <style> #div1{ width: 200px; height: 200px; background: red; border: 1px solid black; } #div2{ height: 200px; background: red; border: 1px solid black; } #div3{ width: 200px; height: 200px; background: red; border: 1px solid black; } </style> <script> setInterval(function () { var oDiv1 = document.getElementById(‘div1‘); oDiv1.style.width = oDiv1.offsetWidth-1+‘px‘; //问题来了,样式表中未加“border”之前,div确实在一直变窄,直至消失,而加入“border”之后div就开始慢慢变宽了, //原因是,offsetwidth获得的是div的“盒模型”(其中包括:border、padding、width等等)尺寸,究其根本原因是 //因为width=200 左右border为2 offsetWidth=200+2=202,202-1=201px赋值给Width; //现在offsetWidth=201+2=203px 203-1=202px再赋值给Width; //offsetWidth=202+2=204px 204-1=203px再赋值给Width;如此继续,Width会越来越大,div的宽度也就越来越宽 // //另外,同理,当改为:“oDiv.style.width = oDiv.offsetWidth-2+‘px‘;”时,原先offsetWidth=200+2=202px, //offsetWidth-2=200px赋值给width,offsetWidth有等于200+2px,如此反复,width始终等于200px, //offsetWidth始终等于202px,所以当“-2”时,div不发生任何变化, }, 30); //解决办法是不使用offsetWidth 如下,把div2的width放到行间 setInterval(function () { var oDiv2 = document.getElementById(‘div2‘); oDiv2.style.width = parseInt(oDiv2.style.width)-1+‘px‘; }, 30); //上述解决办法,又存在一个局限性,因为“a.style.b”只能获取行间样式,而不能获取样式表中的样式,解决办法是: function getStyle(obj, name){ //该方法帮助我们获取非行间(样式表里的)样式 if(obj.currentStyle){ return obj.currentStyle[name]; } else { return getComputedStyle(obj, false)[name]; } } setInterval(function () { var oDiv3 = document.getElementById(‘div3‘); oDiv3.style.width = parseInt(getStyle(oDiv3, ‘width‘))-1+‘px‘; }, 30); </script> </head> <body> <div id="div1"></div> <div id="div2" style="width: 200px"></div> <div id="div3"></div> </body> </html>
原有运动框架的问题:只能让某个值运动起来,如果想让其他值运动起来,要修改程序
由上述代码我们可以看出,offset...存在相应的bug,所以之前用过offset...的相关代码也会有同样的错误出现,开始用“offset...”仅仅是因为它比较简单,而且很容易让人们理解运动的概念,但是之后为了避免此类错误的出现,我们就不再优先考虑offset...了,所以下面改进版的“任意值的运动框架-改进版”如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>任意值变化框架-改进版</title> <style> div{ width: 200px; height: 200px; margin: 20px; float: left; background: red; font-size: 14px; border: 1px solid blue; } </style> <script> window.onload = function () { var oDiv1 = document.getElementById(‘div1‘); oDiv1.onmouseover = function () { startMove(this, ‘height‘, 400); }; oDiv1.onmouseout = function (){ startMove(this, ‘height‘, 200); }; var oDiv2 = document.getElementById(‘div2‘); oDiv2.onmouseover = function () { startMove(this, ‘width‘, 400); }; oDiv2.onmouseout = function (){ startMove(this, ‘width‘, 200); }; var oDiv3 = document.getElementById(‘div3‘); oDiv3.onmouseover = function () { startMove(this, ‘font-size‘, 24); //font-size也可以写成fontSize }; oDiv3.onmouseout = function () { startMove(this, ‘fontSize‘, 14); //font-size也可以写成fontSize } var oDiv4 = document.getElementById(‘div4‘); oDiv4.onmouseover = function () { startMove(this, ‘border-width‘, 24); //border-width也可以写成borderWidth }; oDiv4.onmouseout = function () { startMove(this, ‘border-width‘, 1); //border-width也可以写成borderWidth } }; function getStyle(obj, name){ //该方法帮助我们获取非行间(样式表里的)样式 if(obj.currentStyle){ return obj.currentStyle[name]; } else { return getComputedStyle(obj, false)[name]; } } function startMove(obj, attr, iTarget) { clearInterval(obj.timer); obj.timer = setInterval(function () { var cur = parseInt(getStyle(obj, attr)); var speed = (iTarget-cur)/6; speed = speed>0?Math.ceil(speed):Math.floor(speed); if (cur==iTarget) { clearInterval(obj.timer); } else { obj.style[attr] = cur+speed+‘px‘; } }, 30); } </script> </head> <body> <div id="div1">变长</div> <div id="div2">变宽</div> <div id="div3">字体变大</div> <div id="div4">变宽</div> </body> </html>
扩展的运动框架:
运动属性作为参数
封装opacity
小数的问题
但是由于我们在上述代码中用的是:parseInt()进行取整,但是如果我们在使用透明度的时候都需要用到小数,所以此时由于parseInt()的使用,又限制了程序的完整性,解决办法如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>parseInt局限的改进</title> <style> div{ width: 200px; height: 200px; margin: 20px; float: left; background: red; font-size: 14px; border: 10px solid blue; filter: alpha(opacity: 30); /*IE浏览器 物体透明度*/ opacity: 30%; /*Chrome、FF浏览器 物体透明度,也可以写成0.3*/ } </style> <script> window.onload = function () { var oDiv1 = document.getElementById(‘div1‘); oDiv1.onmouseover = function () { startMove(this, ‘opacity‘, 100); }; oDiv1.onmouseout = function (){ startMove(this, ‘opacity‘, 30); }; }; function getStyle(obj, name){ //该方法帮助我们获取非行间(样式表里的)样式 if(obj.currentStyle){ return obj.currentStyle[name]; } else { return getComputedStyle(obj, false)[name]; } } function startMove(obj, attr, iTarget) { clearInterval(obj.timer); obj.timer = setInterval(function () { var cur = 0; if (attr == ‘opacity‘) { cur = Math.round(parseFloat(getStyle(obj, attr))*100); //乘以100符合咱们平时对opacity的设置 Math.round()下面会有介绍 } else { cur = parseInt(getStyle(obj, attr)); } var speed = (iTarget-cur)/6; speed = speed>0?Math.ceil(speed):Math.floor(speed); if (cur==iTarget) { clearInterval(obj.timer); } else { if (attr == ‘opacity‘) { obj.style.filter = ‘alpha(opacity:‘+(cur+speed)+‘)‘; //IE透明度 obj.style.opacity = (cur+speed)/100; var oTxt = document.getElementById(‘txt1‘); oTxt.value = obj.style.opacity; } else { obj.style[attr] = cur+speed+‘px‘; } } }, 30); } // alert(0.06*100); //返回值为 6 没错 // alert(0.07*100); //返回值为:7.000000000000001,出现误差, // // 这是由于计算机存储容量有限,所以计算机并不一定会全部存储数据的实际值,而是近似值,但是只要是近似值就会有误差, // // 但是这并不会妨碍我们的使用,而且并不是PC存在这个问题,手机等计算设备都会有这种问题。 // // 目前这种情况已经相对很少出现了,当然我们也有解决办法 Math.round() 四舍五入 // alert(Math.round(3.499999999999999)); //返回值为3 // alert(Math.round(3.4999999999999999)); //返回值为4 </script> </head> <body> <div id="div1">变长</div> <input id="txt1" type="text"/> </body> </html>
仿Flash图片展示 - 1
效果思路:
两边的按钮——淡入淡出
大图下拉——层级、高度变化
下方的li——多物体淡入淡出
下方的ul——位置计算
左右按钮
淡出淡入
鼠标移动到按钮上,按钮会消失
层级问题
按钮和遮罩上都得加上事件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>仿Flash图片轮转效果</title> <link rel="stylesheet" type="text/css" href="31.css"/> <script src="31JS_StartMove.js"></script> <script> function getByClass(oParent, sClass){ var aEle = oParent.getElementsByTagName("*"); var aResult = []; //存储选出来的结果 for(var i=0; i<aEle.length; i++){ if (aEle[i].className == sClass){ aResult.push(aEle[i]); } } return aResult; } window.onload = function(){ var oDiv = document.getElementById(‘playimages‘); var oBtnPrev = getByClass(oDiv, ‘prev‘)[0]; var oBtnNext = getByClass(oDiv, ‘next‘)[0]; var oMarkLeft = getByClass(oDiv, ‘mark_left‘)[0]; var oMarkRight = getByClass(oDiv, ‘mark_right‘)[0]; var oDivSmall = getByClass(oDiv, ‘small_pic‘)[0]; var oUlSmall = oDivSmall.getElementsByTagName(‘ul‘)[0]; var aLiSmall = oDivSmall.getElementsByTagName(‘li‘); var oUlBig = getByClass(oDiv, ‘big_pic‘)[0]; var aLiBig = oUlBig.getElementsByTagName(‘li‘); var nowZIndex = 2; //用于改变图片的层级,层级越大,图片越靠上,最大层级的图片永远在最上方 var now = 0; //为上一张和下一张做准备 oUlSmall.style.width = aLiSmall.length*aLiSmall[0].offsetWidth+‘px‘; //把放小图的div加宽,使其能放下所有图片 //左右按钮 oBtnPrev.onmouseover = oMarkLeft.onmouseover = function () { startMove(oBtnPrev, ‘opacity‘, 100); }; oBtnPrev.onmouseout = oMarkLeft.onmouseout = function () { startMove(oBtnPrev, ‘opacity‘, 0); }; oBtnNext.onmouseover = oMarkRight.onmouseover = function () { startMove(oBtnNext, ‘opacity‘, 100); }; oBtnNext.onmouseout = oMarkRight.onmouseout = function () { startMove(oBtnNext, ‘opacity‘, 0); }; //大图切换 for (var i=0; i<aLiSmall.length; i++){ aLiSmall[i].index = i; aLiSmall[i].onclick = function(){ //计算当前是哪一张照片,如果是当前显示的图片,点击小图切换是,如果点击的小图和显示的大图对应,则大图没有反应即可,避免图片重复刷新 if (this.index == now) return; now = this.index; tab(); //函数调用 }; aLiSmall[i].onmouseover = function () { startMove(this, ‘opacity‘, 100); }; aLiSmall[i].onmouseout = function () { if (this.index != now) { startMove(this, ‘opacity‘, 60); } } } //函数封装 function tab(){ aLiBig[now].style.zIndex = nowZIndex++; for (var i=0; i<aLiSmall.length;i++){ startMove(aLiSmall[i], ‘opacity‘, 60); } startMove(aLiSmall[now], ‘opacity‘, 100); aLiBig[now].style.height = 0; startMove(aLiBig[now], ‘height‘, 320); //控制大图片转换,转换方式是调整图片高度 if (now == 0){ //当图片是第一张图片时,第一张小图left=0,即靠左放 startMove(oUlSmall, ‘left‘, 0); } else if (now == aLiSmall.length-1){ //当图片为最后一张图片时,最后一张小图靠右摆放 startMove(oUlSmall, ‘left‘, -(now-2)*aLiSmall[0].offsetWidth); } else { //当图片既不是第一张,也不是最后一张时,靠中间摆放 startMove(oUlSmall, ‘left‘, -(now-1)*aLiSmall[0].offsetWidth); } // startMove(oUlSmall, ‘left‘, -(now-1)*aLiSmall[0].offsetWidth) } oBtnPrev.onclick = function () { now--; if (now == -1){ now = aLiSmall.length-1; } tab(); }; oBtnNext.onclick = function () { now++; if (now == aLiSmall.length) { now=0; } tab(); //函数调用 }; //自动播放 var timer = setInterval(oBtnNext.onclick, 2000); oDiv.onmouseover = function () { clearInterval(timer); }; oDiv.onmouseout = function () { timer = setInterval(oBtnNext.onclick, 2000); }; }; </script> </head> <body> <div id="playimages" class="play"> <ul class="big_pic"> <div class="prev"></div> <div class="next"></div> <div class="text">加载图片说明……</div> <div class="length">计算图片数量……</div> <a class="mark_left" href="javascript:;"></a> <a class="mark_right" href="javascript:;"></a> <div class="bg"></div> <li style="z-index: 1;"><img src="img/bg1.jpg"/></li> <li><img src="img/bg2.jpg"></li> <li><img src="img/bg3.jpg"></li> <li><img src="img/bg4.jpg"></li> <li><img src="img/bg5.jpg"></li> <li><img src="img/bg3.jpg"></li> </ul> <div class="small_pic"> <ul style="width: 390px;"> <li style="filter: alpha(opacity: 100); opacity: 1;"><img src="img/bg1.jpg"/></li> <li><img src="img/bg2.jpg"></li> <li><img src="img/bg3.jpg"></li> <li><img src="img/bg4.jpg"></li> <li><img src="img/bg5.jpg"></li> <li><img src="img/bg3.jpg"></li> </ul> </div> </div> </body> </html>
body{background: #666;} ul{padding: 0; margin: 0;} li{list-style: none;} img{border: 0;} .play{ width: 400px; height: 430px; margin: 50px auto 0; background: #999; font: 12px Arial; } .big_pic{ width: 400px; height: 320px; overflow: hidden; border-bottom: 1px solid #ccc; background: #222; position: relative; } .big_pic li{ width: 400px; height: 320px; overflow: hidden; top: 0; left: 0; z-index: 0; background: url("img/loading.jpg") no-repeat center center; position: absolute; } .big_pic li img{ width: 400px; height: 320px; } .mark_left{ width: 200px; height: 320px; position: absolute; left: 0; top: 0; background: red; filter: alpha(opacity:0); opacity: 0; /*控制左右位置,使鼠标停到左边时,左键出现*/ z-index: 3000; } .mark_right{ width: 200px; height: 320px; position: absolute; left: 200px; top: 0; background: green; filter: alpha(opacity:0); opacity: 0; z-index: 3000; } .big_pic .prev{ width: 60px; height: 60px; background: url("img/btn.jpg") no-repeat; position: absolute; top: 130px; left: 10px; z-index: 3001; /*display: none;*/ filter: alpha(opacity:0); opacity: 0; cursor: pointer; } .prev .next img{ width: 60px; height: 60px; } .big_pic .next{ width: 60px; height: 60px; background: url("img/btn.jpg") no-repeat 0 -60px; position: absolute; top: 130px; right: 10px; z-index: 3001; /*display: none;*/ filter: alpha(opacity:0); opacity: 0; cursor: pointer; } .big_pic .text{ position: absolute; left: 10px; top: 302px; z-index: 3000; color: #ccc; } .big_pic .length{ position: absolute; right: 10px; bottom: 4px; z-index: 3000; color: #ccc; } .big_pic .bg{ width: 400px; height: 25px; background: #000; filter: alpha(opacity=60); opacity: 0.6; position: absolute; z-index: 2999; bottom: 0; left: 0; } .small_pic{ width: 380px; height: 94px; position: relative; top: 7px; left: 10px; overflow: hidden; } .small_pic ul{ height: 94px; position: absolute; top: 0px; left: 0px; } .small_pic li{ width: 120px; height: 94px; float: left; padding-right: 10px; background: url("img/loading.jpg") no-repeat center center; cursor: pointer; filter: alpha(opacity=100); opacity: 0.6; } .small_pic li img{ width: 120px; height: 94px; }
function getStyle(obj, name){ //该方法帮助我们获取非行间(样式表里的)样式 if(obj.currentStyle){ return obj.currentStyle[name]; } else { return getComputedStyle(obj, false)[name]; } } function startMove(obj, attr, iTarget) { clearInterval(obj.timer); obj.timer = setInterval(function () { var cur = 0; if (attr == ‘opacity‘) { cur = Math.round(parseFloat(getStyle(obj, attr))*100); //乘以100符合咱们平时对opacity的设置 } else { cur = parseInt(getStyle(obj, attr)); } var speed = (iTarget-cur)/6; speed = speed>0?Math.ceil(speed):Math.floor(speed); if (cur==iTarget) { clearInterval(obj.timer); } else { if (attr == ‘opacity‘) { obj.style.filter = ‘alpha(opacity:‘+(cur+speed)+‘)‘; //IE透明度 obj.style.opacity = (cur+speed)/100; var oTxt = document.getElementById(‘txt1‘); oTxt.value = obj.style.opacity; } else { obj.style[attr] = cur+speed+‘px‘; } } }, 30); }
图片自行找,然后把名字改成文件中的图片名称即可,甚至不用管你找的图片尺寸,因为在CSS样式表中有对图片调整的代码。
仿Flash图片展示 - 2
下方li效果
点击切换大图——选项卡
li淡入淡出——移入移除
ul移动——位置计算
大图片切换
图片层级——zIndex一直加1
图片下拉效果(运动框架)
可改为淡入淡出
加入自动播放
和选项卡一样
重要知识点:
多物体运动
任意值运动
以上是关于第九节 JS运动应用的主要内容,如果未能解决你的问题,请参考以下文章
vue.js项目实战运用篇之抖音视频APP-第九节: 视频上滑下拉播放功能