jquery: 自定义滚动优化

(function (win, doc, $) {
    function CustomScrollBar(options) {
        this._init(options);
    }
    $.extend(CustomScrollBar.prototype, {
        // this -> CustomScrollBar
        _init: function (options) {
            let _this = this;
            _this.options = {
                scrollDir: 'y', //滚动方向
                contentSelector: '', //滚动内容区选择器(样式带有overflow为hidden的)
                sliderSelector: '',  //滚水滑块选择器
                barSeletor: '', //滚动条选择器
                wheelStep: 10 //滚轮步长
            }
            $.extend(true, _this.options, options || {}); //深拷贝的方式合并两个对象
            _this._initDomEvent();
            return _this;
        },
        _initDomEvent: function () {
            let opts = this.options;
            // 获取相应Jquery对象
            this.$scrollContent = $(opts.contentSelector);
            this.$scrollSlider = $(opts.sliderSelector);
            this.$scrollBar = opts.barSeletor ? $(opts.barSeletor) : _this.$scrollSlider.parent();
            this.$doc = $(doc);
            this._initSliderHeight();
            this._initSliderDragEvent();
            this._bindMousewheel();
            this._bindContentScroll();
        },
        _initSliderHeight: function () {
            let _this = this;
            let sliderHeight;
            let contentHeight = _this.$scrollContent.height();
            let contentTotalHeight = _this.$scrollContent[0].scrollHeight;
            let offsetHeight = contentTotalHeight - contentHeight;
            if (offsetHeight <= 0) {
                sliderHeight = 0;
                _this._unbindMouseOver();
            } else {
                sliderHeight = contentHeight * contentHeight / contentTotalHeight;
                _this._bindMouseHover();
            }
            _this.$scrollSlider.height(`${sliderHeight}px`);
            return _this;
        },
        _unbindMouseOver: function () {
            this.$scrollBar.hide();
            this.$scrollContent.off('mouseenter mouseleave');
        },
        _bindMouseHover: function () {
            let _this = this;
            this.$scrollContent.on({
                mouseenter: function () {
                    _this.$scrollBar.show();
                },
                mouseleave: function () {
                    _this.$scrollBar.hide();
                }
            })
        },
        _initSliderDragEvent: function () {
            let _this = this;
            let slider = _this.$scrollSlider;
            let sliderElement = slider[0];
            if (sliderElement) {
                let doc = _this.$doc;
                let startScrollTop;
                let startPagePosition;
                let contentBarRate;
                function mousemoveHandler(sliderEvent) {
                    event.preventDefault();
                    //判断是否按下鼠标
                    if (startPagePosition == null) {
                        return;
                    }
                    // 内容可移动距离/滑块可移动距离 = 内容移动距离/滑块移动距离
                    let endPagePosition = sliderEvent.pageY
                    let sliderMoveDistance = endPagePosition - startPagePosition;
                    let contentMoveDistance = contentBarRate * sliderMoveDistance;
                    let endScrollTop = startScrollTop + contentMoveDistance;
                    _this.scrollTo(endScrollTop);
                }
                slider.on('mousedown', function (sliderEvent) {
                    sliderEvent.preventDefault();
                    startPagePosition = sliderEvent.pageY; //clientY
                    //获取可视区Top到移出可视区Top的距离
                    startScrollTop = _this.$scrollContent.scrollTop();
                    //获取内容可滚动高度与滑块可滚动高度比率
                    contentBarRate = _this.getContentMaxMovableDistance() / _this.getSliderMaxMovableDistance();
                    //.scroll命名空间,防止停止doc事件
                    doc.on('mousemove.scroll', mousemoveHandler)
                        .on('mouseup.scroll', function () {
                            doc.off('.scroll');
                        })
                });
            }
            return _this;
        },
        //监听滚动内容,同步滑块位置
        _bindContentScroll: function () {
            let _this = this;
            _this.$scrollContent.on('scroll', function () {
                let sliderElement = _this.$scrollSlider && _this.$scrollSlider[0];
                if (sliderElement) {
                    sliderElement.style.top = _this.getSliderPosition() + 'px';
                }
            })
            return _this;
        },
        //监听滚轮事件
        _bindMousewheel: function () {
            let _this = this;
            let scrollContent = _this.$scrollContent;
            scrollContent.bind('mousewheel DOMMouseScroll', function (contentEvent) {
                contentEvent.preventDefault();
                let originEvent = contentEvent.originalEvent;
                //滚动幅度:wheelDelta 其他浏览器120, Firefox:3
                let wheelRange = originEvent.wheelDelta ? -originEvent.wheelDelta / 120 : (originEvent.detail || 0) / 3;
                let startScrollTop = scrollContent.scrollTop();
                let wheelMoveDistance = wheelRange * _this.options.wheelStep;
                _this.scrollTo(startScrollTop + wheelMoveDistance);
            });
            return _this;
        },
        //计算当前滑块位置
        getSliderPosition: function () {
            let _this = this;
            // 滑块移动距离/滑块可移动距离 = 内容移动距离/内容可移动距离
            let sliderMaxMovableDistance = _this.getSliderMaxMovableDistance();
            let contentMaxMovableDistance = _this.getContentMaxMovableDistance();
            let contentMoveDistance = _this.$scrollContent.scrollTop();
            let sliderMoveDistance = sliderMaxMovableDistance * contentMoveDistance / contentMaxMovableDistance;
            return Math.min(sliderMaxMovableDistance, sliderMoveDistance)
        },
        //获取内容可滚动高度 = 内容总高度 - 内容可视区高度
        getContentMaxMovableDistance: function () {
            let _this = this;
            let contentHeight = _this.$scrollContent.height();
            let contentTotalHeight = _this.$scrollContent[0].scrollHeight;
            return Math.max(contentHeight, contentTotalHeight) - contentHeight
        },
        // 获取滑块可移动高度 = 滚动条高度 - 滑块高度
        getSliderMaxMovableDistance: function () {
            let _this = this;
            let barHeight = _this.$scrollBar.height();
            let sliderHeight = _this.$scrollSlider.height();
            return barHeight - sliderHeight;
        },
        scrollTo: function (endScrollTop) {
            let _this = this;
            _this.$scrollContent.scrollTop(endScrollTop);
        }
    })
    win.CustomScrollBar = CustomScrollBar;
})(window, document, jQuery);

// 根据不同类型获取滚动实例
function getCustomScrollBarInstance(tagId) {
    let params = {
        contentSelector: `#${tagId} .scroll-content`,
        sliderSelector: `#${tagId} .scroll-slider`,
        barSeletor: `#${tagId} .scroll-bar`,
        wheelStep: 20
    }
    return new CustomScrollBar(params);
}

 

posted @ 2020-08-17 16:14  Nyan  阅读(212)  评论(0编辑  收藏  举报