javascript动画系列第五篇——模拟滚动条

前面的话

  当元素内容溢出元素尺寸范围时,会出现滚动条。但由于滚动条在各浏览器下表现不同,兼容性不好。所以,模拟滚动条也是很常见的应用。本文将详细介绍滚动条模拟

原理介绍

  滚动条模拟实际上和元素模拟拖拽类似。仅仅通过范围限定,使元素只可以在单一方向上拖拽

<div id="box" style="height: 200px; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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=" 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; 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; 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=" 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>

原文地址:https://www.cnblogs.com/xiaohuochai/p/5901426.html