zoukankan      html  css  js  c++  java
  • 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);
    }
  • 相关阅读:
    vue中computed和watch的区别,以及适用场景
    vue中使用过的全局API
    厦门中控
    设置圆角的弧度,保持兼容性
    伪元素::after和::before
    SpringMVC
    mui问题
    错误记录
    Android错误
    Android之界面(布局文件layput)
  • 原文地址:https://www.cnblogs.com/Nyan-Workflow-FC/p/13518293.html
Copyright © 2011-2022 走看看