jQuery插件开发之windowScroll
回首望,曾经洋洋得意的代码现在不忍直视。曾经看起来碉堡的效果现在也能稍微弄点出来。社会在往前发展,人也得向前迈进。
参考于搜狗浏览器4.2版本首页的上下滚动效果。主要实现整个窗口的上下和左右滚动逻辑,还有很多可以拓展的空间。希望大家能多提意见与建议。
欢迎fork项目:https://github.com/codetker/myWindowScroll, 实现的效果见http://www.梦萦无双.xyz/myWindowScroll/demo/Default.html, 应用见http://wechat.wutnews.net/Web/PhotoWall/(尚在改善中)。
插件效果:
实现window的上下滚动,默认绑定键盘上下按钮和鼠标滑轮
实现window的左右滚动,默认绑定键盘左右按钮
可附加ul li协助控制滚动
可修改后附加缓动函数,实现多种效果,详情见缓动函数表 http://easings.net/zh-cn#easeInOutQuad
html 结构(ZenCoding形式)
-div.divClass
-div.toLeftOrTop
-div.toRightOrBottom
-div.stageClass*n
-ul.controlUl
-li.liClass*n
其中div.toLeftOrTop,div.toRightOrBottom,ul.controlUl可选
调用方法(详情见demo)(按需设置参数)
A.vertical
$(".divClass").windowScroll({ 'choose': 0, //垂直滚动,默认 'verticalSpeed': 1, //控制垂直滚动速度 'objControlUl': 'ul.controlUl', //控制垂直滚动按钮,默认为null 'list': '.stageClass', //垂直滚动的对象 'crash': true, //撞击底部特效 'toTop': '.toLeftOrTop', //向上按钮,默认为null 'toBottom': 'toRightOrBottom', //向下按钮,默认为null 'liHover': 'stageSelect' //设置当前stage的类名 });
B.horizontal
$(".divClass").windowScroll({ 'choose': 1, //水平滚动 'horizontalSpeed': 1, //控制水平滚动速度 'objControlUl': 'ul.controlUl', //控制水平滚动按钮,默认为null 'list': '.stageClass', //水平滚动的对象 'crash': true, //撞击左右特效 'toTop': '.toLeftOrTop', //向左按钮,默认为null 'toBottom': 'toRightOrBottom', //向右按钮,默认为null 'liHover': 'stageSelect' //设置当前page的类名 });
运行demo
最简单的方法为改Default.html中jquery对应script元素的src为本地的jquery(离线)或CDN中的jquery(在线),然后双击Default.html即可
或者配置myBoxScroll.jquery.json or package.json
PS:代码之间耦合过强,可重复利用的很多,准备参考学长的建议按模块写个人函数库,通过模块加载注入需要使用的工具函数
Demo代码如下:
HTML
<!doctype html> <html> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta content="" name="keywords" /> <meta content="" name="description" /> <meta name="author" content="codetker" /> <head> <title>window对象滚动插件</title> <link href="style/reset.css" rel="stylesheet" type="text/css"> <link href="style/style.css" rel="stylesheet" type="text/css"> <script type="text/javascript" src="../src/jquery-1.9.1.min.js"></script> <script type="text/javascript" src="../dest/jquery.codetker.windowScroll.min.js"></script> </head> <body scroll="no"> <div class="wrap" style="dispaly:block;"> <div class="stageControl"> <ul> <li class="stageSelect">stage1</li> <li>stage2</li> <li>stage3</li> <li>stage4</li> <li>stage5</li> </ul> </div> <div class="toTop">Top</div> <div class="toBottom">Bottom</div> <div class="stage stage1"> <div class="pageControl"> <ul> <li class="pageSelect">page1</li> <li>page2</li> <li>page3</li> </ul> </div> <div class="toLeft">Left</div> <div class="toRight">Right</div> <div class="page page1"></div> <div class="page page2"></div> <div class="page page3"></div> </div> <div class="stage stage2"></div> <div class="stage stage3"></div> <div class="stage stage4"></div> <div class="stage stage5"></div> </div> <script type="text/javascript"> $(document).ready(function() { $(".wrap").windowScroll({ 'choose': 0, 'verticalSpeed': 1, 'objControlUl': '.wrap .stageControl', 'list': '.wrap .stage', 'crash': true, 'toTop': '.toTop', 'toBottom': '.toBottom', 'liHover': 'stageSelect' }); $(".stage1").windowScroll({ 'choose': 1, 'horizontalSpeed': 1, 'objControlUl': '.stage1 .pageControl', 'list': '.stage1 .page', 'crash': true, 'toLeft': '.toLeft', 'toRight': '.toRight', 'liHover': 'pageSelect' }); }); </script> </body> </html>
CSS
@charset "utf-8"; /* CSS Document */ /* whole */ body{ margin : 0 0; padding : 0 0; height : 100%; width : 100%; overflow: hidden;; } .wrap{ font-family: "微软雅黑","宋体", Times, "Times New Roman", serif; font-size : 14px; margin : 0 0; padding : 0 0; height : 100%; width : 100%; overflow : hidden; } /* whole end */ /* stage */ .stage,.page{ width : 100%; height: 100%; } .stage1{ background-color: #b9f579; } .stage2{ background-color: #d87efa; } .stage3{ background-color: #f97171; } .stage4{ background-color: #ffc438; } .stage5{ background-color: #9ff4d5; } .stageControl{ position: fixed; } .stageControl ul li{ -webkit-transition-duration: 0.3s; -o-transition-duration : 0.3s; transition-duration : 0.3s; /* 兼容低版本IE,add PIE.htc or IE-css3.htc here */ } .stageSelect{ background-color: #888 !important; } /* stage end */ /* page */ .page{ float: left; } .page2{ background-color: #fca172; } .page3{ background-color: #b6befc; } .pageControl{ position: absolute; left : 200px; } .pageControl ul li{ float : left; -webkit-transition-duration: 0.3s; -o-transition-duration : 0.3s; transition-duration : 0.3s; /* 兼容低版本IE,add PIE.htc or IE-css3.htc here */ } .pageSelect{ background-color: #888 !important; } /* page end */ /* left,right,top,bottom button */ .toTop,.toBottom{ position: fixed; } .toTop{ top :180px; } .toBottom{ top :220px; } .toLeft,.toRight{ position: absolute; } .toLeft{ left: 600px; } .toRight{ left: 720px; } .toLeft,.toRight,.toTop,.toBottom,.pageControl ul li,.stageControl ul li{ width : 100px; height: 30px; line-height: 30px; text-align : center; cursor: pointer; color : #fff; background-color: #aaa; } .toLeft:hover,.toRight:hover,.toTop:hover,.toBottom:hover,.pageControl ul li:hover,.stageControl ul li:hover{ background-color: #888; } /* left,right,top,bottom button end */
JavaScript
/* * windowScroll 0.1 * window滚动插件,上下左右,可选择是否回弹。参考搜狗欢迎页面 * 兼容等常见浏览器 * 借鉴搜狗4.2版http://ie.sogou.com/features4.2.html */ ;(function($, window, document, undefined) { //定义构造函数 var WindowObj = function(ele, opt) { this.$element = ele; this.defaults = { 'choose': 0, 'list': null, 'verticalSpeed': 1, 'horizontalSpeed': 1, 'objControlUl': null, 'toLeft': null, 'toRight': null, 'toTop': null, 'toBottom': null, 'crash': true, 'liHover': null }; this.options = $.extend({}, this.defaults, opt); }; //给构造函数添加方法 WindowObj.prototype = { //上下滚动的方法 verticalMove: function() { var obj = this.$element, speed = this.options.verticalSpeed, objControl = this.options.objControlUl, controlList = $(objControl).find('li'), windowHeight = $(window).height(), list = this.options.list, listMax = $(list).length, toTop = this.options.toTop, toBottom = this.options.toBottom, crashButton = this.options.crash, liHover = this.options.liHover, stop = 0, stageIndex, windowobject = is_chrome(); function setCss() { $(obj).css({ 'width': $(window).width() + 'px', 'height': $(window).height() * listMax + 'px' }); $(list).css({ 'min-width': $(window).width() + 'px', 'height': $(window).height() + 'px' }); } setCss(); function markStage() { getIndex(); $(controlList).removeClass(liHover); $(controlList).eq(stageIndex).addClass(liHover); } function is_chrome() { var is_ch = navigator.userAgent.toLowerCase().indexOf('chrome') > -1; if (is_ch) { //判断webkit内核,供scrollTop兼容性使用 return 'body'; } else { //支持IE和FF return 'html'; } } //阻止默认行为和冒泡 function stopDefaultAndBubble(e) { e = e || window.event; if (e.preventDefault) { e.preventDefault(); } e.returnValue = false; if (e.stopPropagation) { e.stopPropagation(); } e.cancelBubble = true; } //得到当前的垂直位置 function getIndex() { stageIndex = Math.round($(window).scrollTop() / windowHeight); } function goTop() { getIndex(); scrollStage(windowobject, stageIndex, 1); } function goBottom() { getIndex(); scrollStage(windowobject, stageIndex, -1); } //绑定键盘上下按键事件 $(document).keydown(function(event) { /* 绑定keycode38,即向上按钮 */ if (event.keyCode == 38) { goTop(); } else if (event.keyCode == 40) { //绑定40,即向下按钮 goBottom(); } }); //绑定滑轮功能的函数 function handle(delta) { getIndex(); if (delta < 0) { scrollStage(windowobject, stageIndex, -1); //stageIndex为当前页码 } else { scrollStage(windowobject, stageIndex, 1); //stageIndex为当前页码 } } //判断滑轮,解决兼容性 function wheel(event) { var delta = 0; if (!event) event = window.event; if (event.wheelDelta) { delta = event.wheelDelta; if (window.opera) delta = -delta; } else if (event.detail) { delta = -event.detail; } if (delta) handle(delta); //调用执行函数 } //注册事件 if (window.addEventListener) { window.addEventListener('DOMMouseScroll', wheel, false); } window.onmousewheel = document.onmousewheel = wheel; //绑定鼠标滚轮事件 $(document).bind('mousedown', function(e) { if (e.which == 2) { //which=2代表鼠标滚轮,即为中键 stopDefaultAndBubble(e); //bugfix 搜狗浏览器的ie内核只有在定时器触发这个函数才生效 setTimeout(function() { stopDefaultAndBubble(e); }, 10); } }); //如果有ul li控制按钮 if (objControl !== null) { $(objControl).delegate('li', 'click', function() { stageIndex = $(this).index(); scrollStage(windowobject, stageIndex, 0); }); } //如果有上下控制 $(toTop).click(function() { goTop(); }); $(toBottom).click(function() { goBottom(); }); function scrollStage(obj, stIndex, dir) { var sIndex = stIndex, windowobject = obj, direction = 0 || dir, target = windowHeight * sIndex; function move() { $(windowobject).animate({ 'scrollTop': target + 'px' }, 1000 * speed, function() { crash(1, target, 20, 150, -1); markStage(); }); } function after_crash(distant, time, termin) { if (distant <= 15 || time > 150) { stop = 1; //停止碰撞 $(windowobject).animate({ 'scrollTop': termin + 'px' }, time, function() { stop = 0; }); } } //撞击函数 function crash(direction, termin, distant, time, aspect) { if (crashButton) { if (!stop) { if (direction === 1) { direction = 0; if (aspect === 1) { $(windowobject).animate({ 'scrollTop': '-=' + distant + 'px' }, time, function() { crash(direction, termin, distant * 0.6, time, 1); after_crash(distant, time, termin); }); } else { $(windowobject).animate({ 'scrollTop': '+=' + distant + 'px' }, time, function() { crash(direction, termin, distant * 0.6, time, -1); after_crash(distant, time, termin); }); } } else if (direction === 0) { direction = 1; if (aspect === 1) { $(windowobject).animate({ 'scrollTop': termin + 'px' }, time, function() { crash(direction, termin, distant * 0.6, time, 1); after_crash(distant, time, termin); }); } else { $(windowobject).animate({ 'scrollTop': termin + 'px' }, time, function() { crash(direction, termin, distant * 0.6, time, -1); after_crash(distant, time, termin); }); } } } } } if (!$(windowobject).is(':animated')) { switch (direction) { case 0: if ($(window).scrollTop() > target) { direction = -1; move(); } else if ($(window).scrollTop() == windowHeight * sIndex) { direction = 0; crash(1, target, 20, 150, -1); } else { direction = 1; move(); } break; case 1: if (sIndex === 0) { crash(1, target, 20, 150, 1); } else { sIndex -= 1; target = windowHeight * sIndex; move(); } break; case -1: if (sIndex === listMax - 1) { crash(1, target, 20, 150, -1); } else { sIndex += 1; target = windowHeight * sIndex; move(); } break; default: } } } }, //左右滚动 horizontalMove: function() { var obj = this.$element, speed = this.options.horizontalSpeed, objControl = this.options.objControlUl, controlList = $(objControl).find('li'), windowWidth = $(window).width(), list = this.options.list, listMax = $(list).length, liHover = this.options.liHover, toLeft = this.options.toLeft, toRight = this.options.toRight, crashButton = this.options.crash, pageIndex; function setCss() { $(obj).css({ 'width': windowWidth * listMax + 'px', 'height': $(window).height() + 'px' }); $(list).css({ 'width': windowWidth + 'px', 'min-height': $(window).height() + 'px' }); } setCss(); function markPage() { getPageIndex(); $(controlList).removeClass(liHover); $(controlList).eq(pageIndex).addClass(liHover); } function getPageIndex() { pageIndex = (-1) * Math.round(parseInt($(obj).css('margin-left')) / windowWidth); } function goLeft() { getPageIndex(); scrollPage(obj, pageIndex, 1); } function goRight() { getPageIndex(); scrollPage(obj, pageIndex, -1); } //绑定键盘左右按键事件 $(document).keydown(function(event) { //判断event.keyCode为39(即向右按钮) if (event.keyCode === 39) { goRight(); } //判断event.keyCode为37(即向左按钮 else if (event.keyCode === 37) { goLeft(); } }); //如果有ul li控制按钮 if (objControl !== null) { $(objControl).delegate('li', 'click', function() { pageIndex = $(this).index(); scrollPage(obj, pageIndex, 0); }); } //如有有左右控制按钮 $(toLeft).click(function() { goLeft(); }); $(toRight).click(function() { goRight(); }); function scrollPage(obj, pageIndex, dir) { var windowobject = obj, direction = 0 || dir, dist = Math.round(parseInt($(obj).css('margin-left'))), aim; function getAim() { aim = pageIndex * windowWidth * (-1); } function crash(type) { if (crashButton) { if (type === 'left') { $(windowobject).animate({ 'margin-left': '+=' + '50px' }, 500).animate({ 'margin-left': '-=' + '100px' }, 500).animate({ 'margin-left': '+=' + '50px' }, 500); } else { $(windowobject).animate({ 'margin-left': '-=' + '50px' }, 500).animate({ 'margin-left': '+=' + '100px' }, 500).animate({ 'margin-left': '-=' + '50px' }, 500); } } } function move() { $(windowobject).animate({ 'margin-left': aim + 'px' }, 1000 * speed, function() { markPage(); }); } if (!$(windowobject).is(':animated')) { switch (direction) { case 0: getAim(); if (dist !== aim) { move(); } else { direction = 0; crash('left'); } break; case 1: if (pageIndex === 0) { crash('left'); } else { pageIndex -= 1; getAim(); move(); } break; case -1: if (pageIndex === (listMax - 1)) { crash('right'); } else { pageIndex += 1; getAim(); move(); } break; default: break; } } } } }; //绑定方法到jquery对象原型上 $.fn.windowScroll = function(options) { var windowObj = new WindowObj(this, options); if (windowObj.options.choose === 0) { return windowObj.verticalMove(); } else if (windowObj.options.choose === 1) { return windowObj.horizontalMove(); } else { //add some functions } }; })(jQuery, window, document);