jQuery实现模拟滚动条效果;
滚动条在web开发中,很常见,原生的HTML滚动条很难看,因此很多网站借助JS来模拟实现滚动条效果;
滚动条的实现原理其实比较简单,拿垂直滚动条来说:
1),最外层容器需要设置overflow:hidden,里层容器的高度(滚动框)一亘高过最外层容器,就会出现右侧绝对定位的滚动条,并且还要在外层容器上面监听鼠标滚轮事件,根据滚动的速度设置右侧滚动条的top值;
2),给右侧滚动条监听鼠标拖动事件,当拖动滚动条的时候,滚动框内的内容会发生相应的滚动,这里就要求计算出滚动框的滚动距离;
3),滚动距离 = 滑块移动距离 ÷ 窗口高度 x 页面长度;
原理虽然简单,但还需再补充一点,由于鼠标的滚轮事件各个浏览器的兼容性存在问题,
在IE和Chrome下通过event.wheelDelta的返回值可以知道滚轮是向上滚的还是向下滚的
当返回值为正值的时候,说明是向上滚
当返回值是负值的时候,说明是向下滚
但是event.wheelDelta在火狐下并不起作用,在火狐下需要通过event.detail来知道滚轮是向上滚的还是向下滚,火狐下还有一点不同:
当返回值为正值的时候,说明是向下滚
当返回值是负值的时候,说明是向上滚
所以需要想办法做个兼容;此处是用jQuery来实现滚动条效果,所以我们借用jQuery Mousewheel这个插件来做兼容;如果用原生JS来实现的话,就需要做兼容了,兼容代码:
/**鼠标滚动事件**/ function wheel(event) { var delta = 0; if (!event) /* For IE. */ event = window.event; if (event.wheelDelta) { /* IE/Opera. */ delta = event.wheelDelta / 120; } else if (event.detail) { /* Mozilla. */ delta = -event.detail / 3; } if (delta) handle(delta); if (event.preventDefault) event.preventDefault(); event.returnValue = false; } if (window.addEventListener) { /** DOMMouseScroll is for mozilla. */ window.addEventListener('DOMMouseScroll', wheel, false); } /** IE/Opera. */ window.onmousewheel = document.onmousewheel = wheel; function handle(delta) { if (delta < 0) { console.log("鼠标滑轮向下滚动:" + delta + "次!"); // 1 return; } else { console.log("鼠标滑轮向上滚动:" + delta + "次!"); // -1 return; } }
直接来看一个demo:http://codepen.io/jonechen/pen/LNrozb;
效果已经基本实现了,不过并不完善;
CSS代码如下:
*{padding:0;margin:0;font:14px/1.8 "microsoft yahei";-moz-user-select:none;/**禁止选中文字*/} .box{width:600px;height:600px;position:relative;border:1px solid #d98d9d;margin:0 auto;overflow:hidden;} .silderBar{width:5px;height:99%;position:absolute;top:0.5%;right:0.5%;background:#bbb;border-radius:5px;overflow:hidden;} .silderBar span{height:20px;width:100%;top:0;left:0;position:absolute;display:block;background:#f90} .content{padding:10px;word-break:break-all;} p{margin-bottom:10px;text-indent:2em;} p+img{max-width:100%;margin:10px auto;display:block;}
HTML代码如下:
<div class="box"> <div class="content"> <h1 style="font-size: 20px;text-align: center;padding: 10px 0">马刺主场大胜灰熊2-0 莱纳德13分邓肯3分9篮板</h1> <p> 网易体育4月20日报道:<br> 圣安东尼奥马刺队在主场扩大优势。米尔斯替补得到16分,莱纳德得到13分,他们带领球队4人得分上双,马刺队在比赛中逐渐发力拉开比分,他们在西部首轮系列赛第二战主场以94-68战胜孟菲斯灰熊队。马刺队把总比分扩大为2-0,双方的第三场将移师孟菲斯进行。 </p> <img src="http://img3.cache.netease.com/photo/0005/2016-04-20/BL3G2K6J4TM10005.jpg" > <p> 马刺队的米尔斯得到16分,莱纳德得到13分,阿尔德里奇得到10分、8个篮板和4次盖帽,马丁得到10分,邓肯得到3分、9个篮板和4次助攻。灰熊队的阿伦得到12分和3个篮板,兰多夫得到11分和12个篮板,巴恩斯得到9分和6个篮板。 </p> <p> 支球队开赛后争夺激烈,场上比分交替增加,马丁两罚一中,首节还有2分55秒时灰熊队以11-13落后。之后的比赛被马刺队掌控,吉诺比利连投带罚得到4分,米尔斯三分中的,他们带领球队打出9-0的小高潮,马刺队以22-11领先11分结束首节。 </p> <p> 阿伦独得4分,他率队在第二节打出8-2的反击波,灰熊队追至21-27。米尔斯挺身而出还击5分,莱纳德、马丁等人轮流得分,半场前3分40秒时马刺队以41-24领先17分。巴恩斯跳投命中,马丁三分命中,帕克跳投得分,马刺队在半场结束时以49-35领先14分。 </p> <p> 马刺队的莱纳德上半场得到9分,米尔斯得到8分;灰熊队的阿伦得到8分,兰多夫得到7分和6个篮板。 </p> <p> 第三节开始后不久阿尔德里奇两次跳投命中,吉诺比利两罚一中,马刺队以63-45领先18分。阿伦连投带罚拿下4分帮助球队追分,米尔斯再中三分,邓肯两罚一中,马刺队在三节结束时以70-53领先。 </p> <p> 安德森连续罚进四球开启第四节,马刺队领先21分。灰熊队打得很顽强,兰多夫独得4分,法玛尔跳投命中,他们帮助球队缩小差距。马刺队的两位老将这时找到准星,他们为球队确立胜局。韦斯特突破扣篮,马丁投中三分,他们各得4分率队打出8-2的攻击波,第四节还有3分15秒时马刺队以88-63领先25分。大比分差距让比赛提前失去悬念,双方都尽遣替补,马刺队以94-68获胜。 </p> <p>灰熊队首发阵容:法玛尔、卡特、巴恩斯、兰多夫、安德森</p> <p>马刺队首发阵容:帕克、格林、莱纳德、阿尔德里奇、邓肯</p> </div> <div class="silderBar"><span></span></div> </div>
JS代码如下:
<script src="http://apps.bdimg.com/libs/jquery/1.10.1/jquery.min.js"></script> <script src="http://cdn.bootcss.com/jquery-mousewheel/3.1.13/jquery.mousewheel.min.js"></script> <script> $(function() { var Box_Height = $(".box").outerHeight(); var content_Height = $(".content").outerHeight(); var bar_Height = $(".silderBar").outerHeight(); var isMouseDown = false; var distance = 0; //滚动条初始高度; var n = Box_Height / content_Height * bar_Height $(".silderBar span").css("height", n) $(".silderBar").mousedown(down); $(window).mousemove(move); $(window).mouseup(up); function down(event) { isMouseDown = true; } function move(event) { event.preventDefault(); distance = event.pageY - $(".silderBar").offset().top; if (isMouseDown == true) { scroll(distance) } } function up() { isMouseDown = false; } // 滚轮事件; $(".box").bind('mousewheel', function(event, delta) { event.preventDefault() var dir = delta > 0 ? 'Up' : 'Down', vel = delta distance = $(".silderBar span").offset().top - $(".box").offset().top; vel > 0 ? distance -= 10 : distance += 10 scroll(distance); }); function scroll(distance) { if (distance < 0) { distance = 0 } else if (distance > bar_Height - $(".silderBar span").outerHeight()) { distance = bar_Height - $(".silderBar span").outerHeight(); } $(".silderBar span").css("top", distance) // 滚动距离 = 滑块移动距离 ÷ 窗口高度 x 页面长度 // var roat = distance / (bar_Height - $(".silderBar span").outerHeight()) // var scroll_distance = parseInt(roat * (content_Height - Box_Height)) var scroll_distance = parseInt(distance / Box_Height * content_Height) $(".content").css("margin-top", -scroll_distance) } }) </script>
插件封装版:http://codepen.io/jonechen/pen/pyOYRM
插件代码:
(function($){ $.fn.scrollBar = function(options) { var defaults = { foregroundColor: 'red', backgroundColor: '#d5d5d5', height: 400, sliderBoxWidth: 10, sliderBarHeight: 100, mousewheel: true, radius:5 } var obj = $.extend(defaults, options); this.each(function(index, el) { var me = $(this); var content = me.children().eq(0); var isMouseDown = false; var distance = 0; me.css({ height: obj.height, position: 'relative' }); if (me.outerHeight() < content.outerHeight()) { var slider = "<div class='slider'><span></span></div>"; me.append(slider); }; if (slider) { var sliderBox = me.find(".slider"), sliderBar = sliderBox.find("span"); var BarHeight = me.outerHeight() / content.outerHeight() * obj.sliderBarHeight; me.css("paddingRight", content.css("paddingLeft")); sliderBox.css({ position: 'absolute', top: 2, right: 2, width: obj.sliderBoxWidth, height: obj.height - 4, background: obj.backgroundColor, borderRadius:obj.radius, overflow:'hidden' }); sliderBar.css({ position: 'absolute', top: 0, right: 0, width: obj.sliderBoxWidth, background: obj.foregroundColor, height: BarHeight, }); sliderBar.on("mousedown", function(event) { event.preventDefault(); isMouseDown = true; }); $(window).on('mousemove', function(event) { event.preventDefault(); distance = event.pageY - me.offset().top if (isMouseDown == true) { scroll(distance) } }); $(window).on('mouseup', function() { isMouseDown = false; }); // 鼠标滚轮事件; if (obj.mousewheel) { me.bind("mousewheel", function(event, delta) { distance = sliderBar.offset().top - me.offset().top; delta > 0 ? distance -= 10 : distance += 10; scroll(distance); }) } function scroll(distance) { if (distance < 0) { distance = 0 } else if (distance > sliderBox.outerHeight() - sliderBar.outerHeight()) { distance = sliderBox.outerHeight() - sliderBar.outerHeight(); } sliderBar.css("top", distance); var scale = distance / (sliderBox.outerHeight() - sliderBar.outerHeight()) var scrollDistance = parseInt(scale * (content.outerHeight() - me.outerHeight())); content.css("marginTop", -scrollDistance) } } }); } })(jQuery)
调用方法:
$('.box').scrollBar({ height:600, })