首页 > 技术文章 > jQuery插件开发之windowScroll

codetker 2015-07-13 20:12 原文

      回首望,曾经洋洋得意的代码现在不忍直视。曾经看起来碉堡的效果现在也能稍微弄点出来。社会在往前发展,人也得向前迈进。

      参考于搜狗浏览器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>
View Code 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 */
View Code CSS

 

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);
View Code JS

 

推荐阅读