//2017-11-06
js模拟滚动条
//滚动条
function Scrollbar(options){
var opts = $.extend({
node : null,
vertical : true,
horizontal : true
},options);
this.node = opts.node;
this.vertical = opts.vertical;
this.horizontal = opts.horizontal;
this.scrollState = true;
this.interval = null;
};
Scrollbar.prototype = {
constructor : Scrollbar,
trigger : function(){
var _this = this;
if(!_this.node || !_this.node.length || (!_this.vertical && !_this.horizontal)){return}
//创建滚动容器
_this.createContainer();
//创建滚动条
_this.createVertical();
_this.createHorizontal();
//重置
_this.handleReset();
//绑定事件
_this.bindEve();
},
//设置重置
handleReset:function(){
var _this = this;
//初始化容器state
_this.initState();
//检测空间
_this.checkVerticalSpace();
_this.checkHorizontalSpace();
//设置容器
_this.setContainer();
//设置垂直滚动条
_this.setVScrollbar();
//设置横向滚动条
_this.setHScrollbar();
},
//创建容器
createContainer:function(){
var _this = this;
if(_this.node.css('position') == 'static'){
_this.node.css({
position : 'relative'
});
}
var $children = _this.node.children().clone(true);
var style = "width:" + _this.node.width() + "px; height:" + _this.node.height() + "px;";
_this.node.html("<div class='vo-scroll-container' style='" + style + "'></div>");
_this.container = _this.node.find('.vo-scroll-container');
_this.container.append($children);
},
//初始化state
initState:function(){
var _this = this;
_this.state = {
height: _this.container.height(),
width: _this.container.width(),
scrollTop: _this.container.scrollTop(),
scrollLeft:_this.container.scrollLeft(),
scrollHeight: _this.container.prop('scrollHeight'),
scrollWidth: _this.container.prop('scrollWidth')
};
},
//设置state
setState:function(params,fn){
var _this = this;
var status = false;
for(var key in params){
if(typeof _this.state[key] == 'undefined' || params[key] == _this.state[key]){
continue;
}
_this.state[key] = params[key];
status = true;
}
if(typeof fn == 'function'){
fn();
}
},
//设置容器
setContainer:function(){
var _this = this;
var style = {};
style.width = _this.state.width + 'px';
style.height = _this.state.height + 'px';
_this.container.css(style);
},
//创建纵向
createVertical:function(){
var _this = this;
if(!_this.vertical){return}
_this.node.append(_this.getScrollHtml('vertical'));
//设置纵向滚动条
_this.vScrollbar = _this.node.find('.vertical');
_this.vStartBtn = _this.vScrollbar.find('.start-button');
_this.vEndBtn = _this.vScrollbar.find('.end-button');
_this.vTrack = _this.vScrollbar.find('.track');
_this.vThumb = _this.vScrollbar.find('.thumb');
//绑定事件
_this.bindVEve();
},
//创建横向
createHorizontal:function(){
var _this = this;
if(!_this.horizontal){return}
_this.node.append(_this.getScrollHtml('horizontal'));
//设置横向滚动条
_this.hScrollbar = _this.node.find('.horizontal');
_this.hStartBtn = _this.hScrollbar.find('.start-button');
_this.hEndBtn = _this.hScrollbar.find('.end-button');
_this.hTrack = _this.hScrollbar.find('.track');
_this.hThumb = _this.hScrollbar.find('.thumb');
//绑定事件
_this.bindHEve();
},
//获取滚动条
getScrollHtml:function(type){
var html = ["<div class='vo-scrollbar " + type + "'>"];
html.push("<b class='start-button vo-null'>上按钮</b>");
html.push("<div class='track'><b class='thumb vo-null'>滑块</b></div>");
html.push("<b class='end-button vo-null'>下按钮</b>");
html.push("</div>");
return html.join('');
},
//检测是否展示纵向滚动条
checkVerticalSpace:function(){
var _this = this;
if(!_this.vertical){return}
//纵向
if(!_this.vScrollbar.is(':visible') && _this.state.height < _this.state.scrollHeight){
_this.vScrollbar.show();
//更新state
_this.setState({
width: _this.state.width - _this.vScrollbar.width()
});
}else if(_this.vScrollbar.is(':visible') && _this.state.height >= _this.state.scrollHeight){
_this.vScrollbar.hide();
//更新state
_this.setState({
width: _this.state.width + _this.vScrollbar.width()
});
}
},
//检测是否展示横向滚动条
checkHorizontalSpace:function(){
var _this = this;
if(!_this.horizontal){return}
//横向
if(!_this.hScrollbar.is(':visible') && _this.state.width < _this.state.scrollWidth){
_this.hScrollbar.show();
_this.setState({
height: _this.state.height - _this.hScrollbar.height()
});
}else if(_this.hScrollbar.is(':visible') && _this.state.width >= _this.state.scrollWidth){
_this.hScrollbar.hide();
_this.setState({
height: _this.state.height + _this.hScrollbar.height()
});
}
},
//设置纵向滚动条
setVScrollbar:function(){
var _this = this;
if(!_this.vertical){return}
//滚动条
var startHeight = _this.vStartBtn.height(),
endHeight = _this.vEndBtn.height(),
trackHeight = _this.state.height - startHeight - endHeight,
thumbHeight = trackHeight * _this.state.height / _this.state.scrollHeight,
thumbTop = _this.state.scrollTop * trackHeight / _this.state.scrollHeight;
//设置滚动条
_this.vScrollbar.css({
height:_this.state.height
});
//设置履带
_this.vTrack.css({
height:trackHeight + 'px'
});
//设置滑块
_this.vThumb.css({
top:Math.ceil(thumbTop) + 'px',
height:Math.ceil(thumbHeight) + 'px'
});
},
//设置垂直滑块
setVThumb:function(){
var _this = this;
thumbTop = _this.state.scrollTop * _this.vTrack.height() / _this.state.scrollHeight;
//设置滑块
_this.vThumb.css({
top:Math.ceil(thumbTop) + 'px'
});
},
//设置横向滚动条
setHScrollbar:function(){
var _this = this;
if(!_this.horizontal){return}
//滚动条
var startWidth = _this.hStartBtn.width(),
endWidth = _this.hEndBtn.width(),
trackWidth = _this.state.width - startWidth - endWidth,
thumbWidth = trackWidth * _this.state.width / _this.state.scrollWidth,
thumbLeft = _this.state.scrollLeft * trackWidth / _this.state.scrollWidth;
//设置滚动条
_this.hScrollbar.css({
width:_this.state.width
});
//设置履带
_this.hTrack.css({
width:trackWidth + 'px'
});
//设置滑块
_this.hThumb.css({
left:Math.ceil(thumbLeft) + 'px',
width:Math.ceil(thumbWidth) + 'px'
});
},
//设置水平滑块
setHThumb:function(){
var _this = this;
thumbLeft = _this.state.scrollLeft * _this.hTrack.width() / _this.state.scrollWidth;
//设置滑块
_this.hThumb.css({
left:Math.ceil(thumbLeft) + 'px'
});
},
//监听scroll事件
listenerScroll:function(){
var _this = this;
return function(){
if(!_this.scrollState){return}
_this.scrollState = false;
var $self = $(this);
setTimeout(function(){
_this.scrollState = true;
//判断是否重置
if(_this.state.scrollHeight != $self.prop('scrollHeight') || _this.state.scrollWidth != $self.prop('scrollWidth')){
_this.handleReset();
return;
}
//纵向
if(_this.state.scrollTop != $self.prop('scrollTop')){
_this.setState({
scrollTop:$self.scrollTop()
},function(){
_this.setVScrollbar();
});
return;
}
//横向
if(_this.state.scrollLeft != $self.prop('scrollLeft')){
_this.setState({
scrollLeft:$self.scrollLeft()
},function(){
_this.setHScrollbar();
});
return;
}
},20);
}
},
//操作滚动条
handleScroll:function(type,val,fn){
var _this = this;
var params = {};
switch(type){
case 'vertical':
params.scrollTop = val;
break;
case 'horizontal':
params.scrollLeft = val;
break;
default:
params = null;
break;
}
if(params == null){return}
_this.container.stop(true).animate(params,20,function(){
if(typeof fn == 'function'){
fn();
}
});
},
//操作滑块
handleThumb:function(type,val){
var _this = this;
switch(type){
case 'vertical':
var top = val * _this.state.scrollHeight / _this.vTrack.height();
_this.container.scrollTop(Math.ceil(top));
break;
case 'horizontal':
var left = val * _this.state.scrollWidth / _this.hTrack.width();
_this.container.scrollLeft(Math.ceil(left));
break;
}
},
//停止计时器
stopInterval:function(){
var _this = this;
if(_this.interval === null){return}
clearInterval(_this.interval);
_this.interval = null;
},
//绑定垂直滚动条事件
bindVEve:function(){
var _this = this;
//上按钮
_this.vStartBtn.on('mousedown',function(){
_this.stopInterval();
_this.interval = setInterval(function(){
_this.handleScroll('vertical',_this.state.scrollTop - 10);
},50);
return false;
});
_this.vStartBtn.on('mouseup mouseleave',function(){
_this.stopInterval();
return false;
});
//下按钮
_this.vEndBtn.on('mousedown',function(){
_this.stopInterval();
_this.interval = setInterval(function(){
_this.handleScroll('vertical',_this.state.scrollTop + 10);
},50);
return false;
});
_this.vEndBtn.on('mouseup mouseleave',function(){
_this.stopInterval();
return false;
});
//拖动
var top = null;
_this.vThumb.vo_mouseDrag({
moveCallback:function(info){
top = top === null ? parseInt($(this).css('top')) : top;
_this.handleThumb('vertical',info.offsetXY.y + top);
},
endCallback:function(){
top = null;
}
});
//滚轮
var wheelState = true;
_this.container.vo_mouseWheel(function(delta){
if(!wheelState || _this.state.height >= _this.scrollHeight){return}
wheelState = false;
_this.handleScroll('vertical',_this.state.scrollTop + (delta > 0 ? -30 : 30),function(){
wheelState = true;
});
});
},
//绑定横向滚动条事件
bindHEve:function(){
var _this = this;
//左按钮
_this.hStartBtn.on('mousedown',function(){
_this.stopInterval();
_this.interval = setInterval(function(){
_this.handleScroll('horizontal',_this.state.scrollLeft - 10);
},50);
return false;
});
_this.hStartBtn.on('mouseup mouseleave',function(){
_this.stopInterval();
return false;
});
//右按钮
_this.hEndBtn.on('mousedown',function(){
_this.stopInterval();
_this.interval = setInterval(function(){
_this.handleScroll('horizontal',_this.state.scrollLeft + 10);
},50);
return false;
});
_this.hEndBtn.on('mouseup mouseleave',function(){
_this.stopInterval();
return false;
});
//拖动
var left = null;
_this.hThumb.vo_mouseDrag({
moveCallback:function(info){
left = left === null ? parseInt($(this).css('left')) : left;
_this.handleThumb('horizontal',info.offsetXY.x + left);
},
endCallback:function(){
left = null;
}
});
},
//绑定事件
bindEve:function(){
var _this = this;
_this.container.on('scroll',_this.listenerScroll());
}
}
//******针对jquery拓展******
$.fn.scrollbar = function(options){
if(!$(this).length){return}
var opts = $.extend({
vertical : true,
horizontal : true
},options);
//循环实例化
$(this).each(function(){
new Scrollbar({
node : $(this),
vertical : opts.vertical,
horizontal : opts.horizontal
}).trigger();
});
};
sCss:
.vo-scroll-container{
overflow: hidden;
}
.vo-scrollbar{
$height:14px;
$width:14px;
position: absolute;
width: $width;
height: $height;
overflow: hidden;
display: none;
cursor: pointer;
.track{
position: relative;
background: #f4f4f4;
}
.thumb{
position: absolute;
background: #fff;
border-radius: 2px;
margin: 1px;
}
.start-button,
.end-button{
width:$width;
height: $height;
background:#f4f4f4 url(../../../image/virgo/scrollbar-icon.png) 0px 0px no-repeat;
}
&.vertical{
top: 0;
right: 0;
height: 100%;
.track{
width: $width;
.thumb{
width:12px;
box-shadow: 0px 2px 10px rgba(0,0,0,0.1);
}
}
.start-button{
background-position: 3px 5px;
&:hover{
background-position: -47px 5px;
}
}
.end-button{
background-position: 3px -45px;
&:hover{
background-position: -47px -45px;
}
}
}
&.horizontal{
bottom: 0;
left: 0;
width: 100%;
.track{
float: left;
height: $height;
.thumb{
height: 12px;
box-shadow: 0px 2px 10px rgba(0,0,0,0.1);
}
}
.start-button,
.end-button{
float: left;
}
.start-button{
background-position: 3px -95px;
&:hover{
background-position: -47px -95px;
}
}
.end-button{
background-position: 3px -145px;
&:hover{
background-position: -47px -145px;
}
}
}
}