javascript动画系列第五篇——模拟滚动条
前面的话
当元素内容溢出元素尺寸范围时,会出现滚动条。但由于滚动条在各浏览器下表现不同,兼容性不好。所以,模拟滚动条也是很常见的应用。本文将详细介绍滚动条模拟
原理介绍
滚动条模拟实际上和元素模拟拖拽类似。仅仅通过范围限定,使元素只可以在单一方向上拖拽
<div id="box" style="height: 200px;width: 16px;background-color:#F5F5F5;border-radius:10px;box-shadow:inset 0 0 6px rgba(0,0,0,0.3);position:relative;"> <div id="test" style="height: 60px;width: 16px;background-color:#555;box-shadow:inset 0 0 6px rgba(0,0,0,.3);border-radius:10px;position:absolute;"></div> </div> <script> function addEvent(target,type,handler){ if(target.addEventListener){ target.addEventListener(type,handler,false); }else{ target.attachEvent('on'+type,function(event){ return handler.call(target,event); }); } } (function(){ var y0,y1,isMoving; var ele = document.getElementById('test'); var mousedownHandler = function(e){ e = e || event; y0 = ele.offsetTop; y1 = e.clientY; //按下鼠标时,表示正在运动 isMoving = true; } var mousemoveHandler = function(e){ //如果没有触发down事件,而直接触发move事件,则函数直接返回 if(!isMoving){ return; } e = e || event; var y2 = e.clientY; var Y = y0 + (y2 - y1); if(Y < 0){Y = 0;} var YMax = parseInt(ele.parentNode.clientHeight) - ele.offsetHeight; if(Y > YMax){Y = YMax;} ele.style.top = Y + 'px'; } var mouseupHandler = function(e){ //鼠标抬起时,表示停止运动 isMoving = false; //释放全局捕获 if(ele.releaseCapture){ ele.releaseCapture(); } } var preventDefaultHandler = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } //IE8-浏览器阻止默认行为 if(ele.setCapture){ ele.setCapture(); } } addEvent(ele,'mousedown',mousedownHandler); addEvent(ele,'mousedown',preventDefaultHandler); addEvent(document,'mousemove',mousemoveHandler); addEvent(document,'mouseup',mouseupHandler); })(); </script>
通过将上面代码封装成函数,可以实现横向和纵向两种滚动条
<div id="box1" style="height: 200px;width: 16px;background-color:#F5F5F5;border-radius:10px;box-shadow:inset 0 0 6px rgba(0,0,0,0.3);position:relative;"> <div id="test1" style="height: 60px;width: 16px;background-color:#555;box-shadow:inset 0 0 6px rgba(0,0,0,.3);border-radius:10px;position:absolute;"></div> </div> <div id="box2" style="height: 16px;width: 200px;background-color:#F5F5F5;border-radius:10px;box-shadow:inset 0 0 6px rgba(0,0,0,0.3);position:relative;"> <div id="test2" style="height: 16px;width: 60px;background-color:#D62929;box-shadow:inset 0 0 6px rgba(0,0,0,.3);border-radius:10px;position:absolute;"></div> </div> <script> function addEvent(target,type,handler){ if(target.addEventListener){ target.addEventListener(type,handler,false); }else{ target.attachEvent('on'+type,function(event){ return handler.call(target,event); }); } } function scrollbar(ele,str){ var x0,x1,y0,y1,isMoving; var mousedownHandler = function(e){ e = e || event; x0 = ele.offsetLeft; y0 = ele.offsetTop; x1 = e.clientX; y1 = e.clientY; //按下鼠标时,表示正在运动 isMoving = true; } var mousemoveHandler = function(e){ //如果没有触发down事件,而直接触发move事件,则函数直接返回 if(!isMoving){ return; } e = e || event; if(str == 'x'){ var x2 = e.clientX; var X = x0 + (x2 - x1); if(X < 0){X = 0;} var XMax = parseInt(ele.parentNode.clientWidth) - ele.offsetWidth; if(X > XMax){X = XMax;} ele.style.left = X + 'px'; }else{ var y2 = e.clientY; var Y = y0 + (y2 - y1); if(Y < 0){Y = 0;} var YMax = parseInt(ele.parentNode.clientHeight) - ele.offsetHeight; if(Y > YMax){Y = YMax;} ele.style.top = Y + 'px'; } } var mouseupHandler = function(e){ //鼠标抬起时,表示停止运动 isMoving = false; //释放全局捕获 if(ele.releaseCapture){ ele.releaseCapture(); } } var preventDefaultHandler = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } //IE8-浏览器阻止默认行为 if(ele.setCapture){ ele.setCapture(); } } addEvent(ele,'mousedown',mousedownHandler); addEvent(ele,'mousedown',preventDefaultHandler); addEvent(document,'mousemove',mousemoveHandler); addEvent(document,'mouseup',mouseupHandler); }; scrollbar(test1); scrollbar(test2,'x'); </script>
应用
下面来介绍通过滚动条实现的几个应用
数字加减
通过移动滚动条来实现数字的加减。比例关系为:
滚动条已移动距离/滚动条可移动距离= 数字当前值/数字最大值
<div id="box" style="height: 16px;width: 200px;display:inline-block;background-color:#F5F5F5;border-radius:10px;box-shadow:inset 0 0 6px rgba(0,0,0,0.3);position:relative;"> <div id="test" style="height: 16px;width: 60px;background-color:#D62929;box-shadow:inset 0 0 6px rgba(0,0,0,.3);border-radius:10px;position:absolute;"></div> </div> <span id="result">0</span> <script> function addEvent(target,type,handler){ if(target.addEventListener){ target.addEventListener(type,handler,false); }else{ target.attachEvent('on'+type,function(event){ return handler.call(target,event); }); } } function scrollbar(ele,str,max){ var x0,x1,y0,y1,isMoving,radio; var mousedownHandler = function(e){ e = e || event; x0 = ele.offsetLeft; y0 = ele.offsetTop; x1 = e.clientX; y1 = e.clientY; //按下鼠标时,表示正在运动 isMoving = true; //x轴方向 if(str == 'x'){ ratio = max/(ele.parentNode.offsetWidth - ele.offsetWidth); //否则为y轴方向 }else{ var disY = e.clientY - ele.offsetTop; ratio =max/(ele.parentNode.offsetHeight - ele.offsetHeight); } } var mousemoveHandler = function(e){ //如果没有触发down事件,而直接触发move事件,则函数直接返回 if(!isMoving){ return; } e = e || event; if(str == 'x'){ var x2 = e.clientX; var X = x0 + (x2 - x1); if(X < 0){X = 0;} var XMax = parseInt(ele.parentNode.clientWidth) - ele.offsetWidth; if(X > XMax){X = XMax;} ele.style.left = X + 'px'; result.innerHTML = Math.round(ratio * X); }else{ var y2 = e.clientY; var Y = y0 + (y2 - y1); if(Y < 0){Y = 0;} var YMax = parseInt(ele.parentNode.clientHeight) - ele.offsetHeight; if(Y > YMax){Y = YMax;} ele.style.top = Y + 'px'; result.innerHTML = Math.round(ratio * Y); } } var mouseupHandler = function(e){ //鼠标抬起时,表示停止运动 isMoving = false; //释放全局捕获 if(ele.releaseCapture){ ele.releaseCapture(); } } var preventDefaultHandler = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } //IE8-浏览器阻止默认行为 if(ele.setCapture){ ele.setCapture(); } } addEvent(ele,'mousedown',mousedownHandler); addEvent(ele,'mousedown',preventDefaultHandler); addEvent(document,'mousemove',mousemoveHandler); addEvent(document,'mouseup',mouseupHandler); }; scrollbar(test,'x',100); </script>
元素尺寸
通过拖动滚动条来实现元素尺寸的变化,以改变元素宽度为例。比例关系为:
滚动条已移动距离/滚动条可移动距离= 元素当前宽度/元素最大宽度
<div id="box" style="height: 16px;width: 200px;display:inline-block;background-color:#F5F5F5;border-radius:10px;box-shadow:inset 0 0 6px rgba(0,0,0,0.3);position:relative;"> <div id="test" style="height: 16px;width: 60px;background-color:#D62929;box-shadow:inset 0 0 6px rgba(0,0,0,.3);border-radius:10px;position:absolute;"></div> </div> <span id="result" style="width: 1px;height: 50px;background-color:pink;display:inline-block;"></span> <script> function addEvent(target,type,handler){ if(target.addEventListener){ target.addEventListener(type,handler,false); }else{ target.attachEvent('on'+type,function(event){ return handler.call(target,event); }); } } function scrollbar(ele,str,max){ var x0,x1,y0,y1,isMoving,radio; var mousedownHandler = function(e){ e = e || event; x0 = ele.offsetLeft; y0 = ele.offsetTop; x1 = e.clientX; y1 = e.clientY; //按下鼠标时,表示正在运动 isMoving = true; //x轴方向 if(str == 'x'){ ratio = max/(ele.parentNode.offsetWidth - ele.offsetWidth); //否则为y轴方向 }else{ var disY = e.clientY - ele.offsetTop; ratio =max/(ele.parentNode.offsetHeight - ele.offsetHeight); } } var mousemoveHandler = function(e){ //如果没有触发down事件,而直接触发move事件,则函数直接返回 if(!isMoving){ return; } e = e || event; if(str == 'x'){ var x2 = e.clientX; var X = x0 + (x2 - x1); if(X < 0){X = 0;} var XMax = parseInt(ele.parentNode.clientWidth) - ele.offsetWidth; if(X > XMax){X = XMax;} ele.style.left = X + 'px'; result.style.width = Math.round(ratio * X) + 'px'; }else{ var y2 = e.clientY; var Y = y0 + (y2 - y1); if(Y < 0){Y = 0;} var YMax = parseInt(ele.parentNode.clientHeight) - ele.offsetHeight; if(Y > YMax){Y = YMax;} ele.style.top = Y + 'px'; result.style.width = Math.round(ratio * Y) + 'px'; } } var mouseupHandler = function(e){ //鼠标抬起时,表示停止运动 isMoving = false; //释放全局捕获 if(ele.releaseCapture){ ele.releaseCapture(); } } var preventDefaultHandler = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } //IE8-浏览器阻止默认行为 if(ele.setCapture){ ele.setCapture(); } } addEvent(ele,'mousedown',mousedownHandler); addEvent(ele,'mousedown',preventDefaultHandler); addEvent(document,'mousemove',mousemoveHandler); addEvent(document,'mouseup',mouseupHandler); }; scrollbar(test,'x',100); </script>
内容滚动
通过拖动滚动条来实现内容滚动,比例关系为:
滚动条已移动距离/滚动条可移动距离= 内容已移动距离/内容可移动距离
<div id="box" style="height: 200px;width: 16px;display:inline-block;background-color:#F5F5F5;border-radius:10px;box-shadow:inset 0 0 6px rgba(0,0,0,0.3);position:relative;vertical-align:middle;"> <div id="test" style="height: 60px;width: 16px;background-color:#D62929;box-shadow:inset 0 0 6px rgba(0,0,0,.3);border-radius:10px;position:absolute;"></div> </div> <span id="result" style="width: 100px;height: 200px;background-color:pink;display:inline-block;line-height:30px;vertical-align:middle;position:relative;overflow:hidden;"><div id="resultIn" style="position:absolute;top:0;">测试文字<br>测试文字<br>测试文字<br>测试文字<br>测试文字<br>测试文字<br>测试文字<br>测试文字<br>测试文字<br>测试文字<br>测试文字<br>测试文字<br></div></span> <script> function addEvent(target,type,handler){ if(target.addEventListener){ target.addEventListener(type,handler,false); }else{ target.attachEvent('on'+type,function(event){ return handler.call(target,event); }); } } function scrollbar(ele,str,max){ var x0,x1,y0,y1,isMoving,radio; var max = result.offsetHeight - resultIn.offsetHeight; var mousedownHandler = function(e){ e = e || event; x0 = ele.offsetLeft; y0 = ele.offsetTop; x1 = e.clientX; y1 = e.clientY; //按下鼠标时,表示正在运动 isMoving = true; //x轴方向 if(str == 'x'){ ratio = max/(ele.parentNode.offsetWidth - ele.offsetWidth); //否则为y轴方向 }else{ var disY = e.clientY - ele.offsetTop; ratio =max/(ele.parentNode.offsetHeight - ele.offsetHeight); } } var mousemoveHandler = function(e){ //如果没有触发down事件,而直接触发move事件,则函数直接返回 if(!isMoving){ return; } e = e || event; if(str == 'x'){ var x2 = e.clientX; var X = x0 + (x2 - x1); if(X < 0){X = 0;} var XMax = parseInt(ele.parentNode.clientWidth) - ele.offsetWidth; if(X > XMax){X = XMax;} ele.style.left = X + 'px'; resultIn.style.left = Math.round(ratio * X) + 'px'; }else{ var y2 = e.clientY; var Y = y0 + (y2 - y1); if(Y < 0){Y = 0;} var YMax = parseInt(ele.parentNode.clientHeight) - ele.offsetHeight; if(Y > YMax){Y = YMax;} ele.style.top = Y + 'px'; resultIn.style.top = Math.round(ratio * Y) + 'px'; } } var mouseupHandler = function(e){ //鼠标抬起时,表示停止运动 isMoving = false; //释放全局捕获 if(ele.releaseCapture){ ele.releaseCapture(); } } var preventDefaultHandler = function(e){ e = e || event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue = false; } //IE8-浏览器阻止默认行为 if(ele.setCapture){ ele.setCapture(); } } addEvent(ele,'mousedown',mousedownHandler); addEvent(ele,'mousedown',preventDefaultHandler); addEvent(document,'mousemove',mousemoveHandler); addEvent(document,'mouseup',mouseupHandler); }; scrollbar(test); </script>
好的代码像粥一样,都是用时间熬出来的