Share the source code of JavaScript scroll bar plug in

  • 2020-05-10 17:40:38
  • OfStack

This is the source code of the js scroll bar plug-in I wrote during the Spring Festival. I am not satisfied with the effect, but I have to go back and reconsolidate and further learn js because I am not satisfied with what I have done. The plug-in has the following unsatisfactory aspects:

For the overuse of the content, see the QQ client's most recent session list for the scroll bar, which is very smooth and simply lacks animated transitions.

Not perfect compatibility, style under IE6 and 7 is still a bit lacking.

The style is not perfect, such as the mouse hover to show the scroll bar, removed after the hidden effect is not written.

Internal structure chaos, need to adjust the content structure.

Scrollbar that picture is not art after all, cut their own graphics are really disgusting to explode... �

In general, it is still viewable, and still lacks 1 animation. After writing this plugin, I realized that my plugin used some basic functions, so I thought of encapsulating these functions. I am still studying js in depth recently. After reading this book, I should start to write the plugin of this basic function. Without further ado, the source code is here (note: the full version of the plug-in is a picture, please download the complete plug-in in the attachment at the end of the article) :

CSS


.lf_Scroll, .lf_Scroll li { padding: 0; margin: 0; list-style: none; font: 14px/24px "Helvetica Neue" ,Helvetica,Arial, 'Microsoft Yahei' ,sans-serif; outline: none; }
.lf_Scroll { cursor: pointer; width: 10px; position: absolute; right: 0; top: 0; filter: alpha(opacity=50); -moz-opacity: 0.5; -khtml-opacity: 0.5; opacity: 0.5; }
.lf_ScrollFocus { filter: alpha(opacity=100); -moz-opacity: 1; -khtml-opacity: 1; opacity: 1; }
.lfs_Top, .lfs_Center, .lfs_Bottom { background: url('ScrollBar.gif'); width: 10px; height: 10px; }
.lfs_Top { background-position: 1px 0px; }
.lfs_Center { background-position: center 0; height: 100px; }
.lfs_Bottom { background-position: -22px 0; }
/*Developers config*/
.rollDiv { height: 100%; width: 100%; overflow: hidden; position: relative; }

JavaScript


/*
* This plugin is defined on the simulation Webpage scroll bar, please insert after binding for DOM events
*
* Comment version: 1.0.0
* Author : linkfly
* Sina: Focus on half a century for you |  cnblogs:http://www.cnblogs.com/silin6/ | Email:linkFly6@live.com
* date : 2014-02-05 02:38:35
*
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/
(function (window, undefined) {
    // Configuration parameter information
    var config = {
        auto: true,
        height: 'auto',
        width: 'auto'
    };
    var linkFlyScroll = function (dom, options) {
        /// <summary>
        ///     1: Generate the simulated scrollbar object, [please bind the event for the object you specified after this object works, otherwise the event you previously bound will not work]
        ///         1.1 - linkFlyScroll(dom) - In the specified dom The scrollbar object is generated on
        ///         1.2 - linkFlyScroll(dom,options) - Generate the scrollbar object, which is also provided 1 Series of parameters allow you to customize the working model for configuring the object
        /// </summary>
        /// <param name="dom" type="String Or element">
        ///     The incoming js the dom Object, or string The object of type ID
        /// </param>
        /// <param name="options" type="Json">
        ///     Customize the working model to configure the object with the following options:
        ///       [ optional ]auto ( Boolean ) : when the content does not reach the height of the container, the scrollbar is automatically hidden by default true( is )
        ///       [ optional ]height ( Int Or String ) : the default unit is px for int and String. A value of auto By default css The height of the
        ///       [ optional ]width ( Int Or String ) : the default unit is px for int and String. A value of auto By default css The width of the
        /// </param>
        /// <returns type="linkFlyScroll" />
        if (typeof (dom) === 'string') {
            dom = document.getElementById(dom);
        }
        // Is not specified dom And not found valid dom
        //linkFlyScroll("") , linkFlyScroll(null) , linkFlyScroll(undefined)
        if (!dom || !dom.nodeType)
            return this;
        // Creating a container object
        var scrollObj = document.createElement('div');
        // Deep cloning of content objects that do not contain events, so wait until linkFlyScroll The object can only be called after it has finished working dom Object binding events
        var cloneObj = dom.cloneNode(true);
        scrollObj.className = 'rollDiv';
        scrollObj.appendChild(cloneObj);
        // Replace the current object on the page
        dom.parentNode.replaceChild(scrollObj, dom);
        return new linkFlyScroll.prototype.init(scrollObj, options ? options : {});
    };
    linkFlyScroll.prototype.init = function (dom, options) {
        /// <summary>
        ///     1: This object is the one that really works, and the particular way it works is because it is possible linkFlyScroll Static calls and instantiated calls
        ///         1.1 - init(dom,options) - In the specified dom The scrollbar object is generated on
        /// </summary>
        /// <param name="dom" type="element">
        ///     dom object
        /// </param>
        /// <param name="options" type="Json">
        ///     Customize the working model to configure the object with the following options:
        ///       [ optional ]auto ( Boolean ) : when the content does not reach the height of the container, the scrollbar is automatically hidden by default true( is )
        ///       [ optional ]height ( Int Or String ) : the default unit is px for int and String. A value of auto By default css The height of the
        ///       [ optional ]width ( Int Or String ) : the default unit is px for int and String. A value of auto By default css The width of the
        /// </param>
        /// <returns type="linkFlyScroll" />
        /*
        * This object contains the following properties:
        * isDrag: Whether you are dragging the scroll bar
        * startTop: The scrollbar starts to scroll
        * endTop: The scroll bar ends at the scroll position
        * topLimit: Limit position at the top of the scroll bar
        * bottomLimit: Scroll bar bottom limit position
        * context: content Dom
        * scrollRadix: Rolling base
        * target: The container Dom
        */
        // The current this Object to prevent this Pointers change frequently in the environment (such as when binding events), so save the current object
        var currScroll = this;
        //DOMElement
        if (dom.nodeType) {
            // Save the container and content DOM
            currScroll.target = dom;
            currScroll.context = dom.firstChild;
            // Merge configuration parameters
            currScroll.options = tool.extend(config, options);
            if (currScroll.options.width !== 'auto') {
                dom.style.width = tool.convertValue(currScroll.options.width);
            }
            if (currScroll.options.height !== 'auto') {
                dom.style.height = tool.convertValue(currScroll.options.height);
            }
            // Find valid dom
            while (currScroll.context.nodeType != 1) {
                currScroll.context = currScroll.context.nextSibling;
            }
            // Create a scroll bar dom
            currScroll.scrollUl = document.createElement('ul');
            currScroll.scrollUl.className = 'lf_Scroll';
            currScroll.scrollUl.appendChild(tool.setClass('li', 'lfs_Top'));
            currScroll.scrollUl.appendChild(tool.setClass('li', 'lfs_Center'));
            currScroll.scrollUl.appendChild(tool.setClass('li', 'lfs_Bottom'));
            currScroll.context.style.position = 'relative';
            // The location data can be read only when it is rendered on the page
            dom.appendChild(currScroll.scrollUl);
            this.change();
            tool.addScrollEvent(currScroll.context, function (e) {
                // Bind the mouse wheel event ,3px Rolling unit
                if (e.wheel > 0) {// The wheel rolls up
                    var currTop = currScroll.endTop -= 3;
                    currScroll.scrollEvent.call(currScroll, currTop);
                } else {// The wheel rolls down
                    var currTop = currScroll.endTop += 3;
                    currScroll.scrollEvent.call(currScroll, currTop);
                }
            });
            // You need to prevent text from being selected while dragging   TODO
            // Click the mouse under the event, need to determine whether left click, right click will also achieve scrolling   TODO
            tool.addEvent(currScroll.scrollUl, 'mousedown', function (e) {
                mouseDown.call(currScroll, e);
            });
            // Append events for a better user experience in body Up implementation listening
            tool.addEvent(document.body, 'mousemove', function (e) {
                if (currScroll.isDrag) {
                    // Gets the current mouse position
                    var position = tool.getMousePos(e);
                    // Current scrollbar top location
                    var currTop = (currScroll.endTop + position.y - currScroll.startTop);
                    //call In order to make this Pointer to the work object
                    currScroll.scrollEvent.call(currScroll, currTop);
                }
                return false;
            });
            // Append the mouse release event in order to accurately capture the release event in body On the monitor
            tool.addEvent(document.body, 'mouseup', function () {
                mouseUp.call(currScroll, []);
            });
            var mouseDown = function (e) {
                /// <summary>
                ///     1: Mouse down event
                ///         1.1 - mouseDown(e) - Mouse down scroll bar event in scroll bar
                /// </summary>
                /// <param name="e" type="Event">
                ///     Event object
                /// </param>
                /// <returns type="linkFlyScroll" />
                currScroll.isDrag = true;
                // Get the current mouse y location
                currScroll.startTop = tool.getMousePos(e).y;
                tool.addClass(currScroll.scrollUl, 'lf_ScrollFocus');
                return false;
            };
            var mouseUp = function () {
                /// <summary>
                ///     1: Mouse release event
                ///         1.1 - mouseUp() - Mouse - released scroll bar event in scroll bar
                /// </summary>
                /// <returns type="linkFlyScroll" />
                currScroll.isDrag = false;
                currScroll.endTop = currScroll.scrollUl.style.top ? parseInt(currScroll.scrollUl.style.top) : 0;
                tool.removeClass(currScroll.scrollUl, 'lf_ScrollFocus');
                return false;
            };
            currScroll.scrollEvent = function (currTop) {
                /// <summary>
                ///     1: Scroll events (core), passing in coordinates that need to be scrolled (scroll bar) top )
                ///         1.1 - scrollEvent(currTop) - Core rolling event
                /// </summary>
                /// <param name="currTop" type="Int">
                ///     Scroll bar top distance 1 Layer of the container top value
                /// </param>
                /// <returns type="void" />
                if (currTop <= currScroll.topLimit || currTop < 0) {// The top limit
                    currTop = currScroll.topLimit;
                } else if (currTop >= currScroll.bottomLimit) {// The bottom limit
                    currTop = currScroll.bottomLimit;
                }
                // Scroll bar offset effect
                currScroll.scrollUl.style.top = currTop + 'px';
                var tempTop = parseInt(currScroll.context.style.top ? currScroll.context.style.top : 0);
                //debug code
                //                document.getElementById('postionInfo').innerHTML = 'currTop:' + currTop + ' Rolling base :' + currScroll.scrollRadix + ' bottomLimit:' + currScroll.bottomLimit + ' endTop:' + currScroll.endTop + ' startTop:' + currScroll.startTop + " Y:" + currTop + " offsetTop:" + currScroll.scrollUl.offsetTop + " compute:" + (currTop * currScroll.scrollRadix * -1) + 'px';
                //text code
                // Content scrolling: current scroll bar top* Negative cardinality
                currScroll.context.style.top = currTop * currScroll.scrollRadix * -1 + 'px';
            };
            return currScroll;
        };
    };
    linkFlyScroll.prototype.init.prototype.change = function () {
        /// <summary>
        ///     1: Scrollbar content changes function
        ///         1.1 - change() - This function represents the refresh of the data of this scrollbar object, in some cases, the data of the content is 1 You can call this function to refresh the data on the current scroll bar object
        /// </summary>
        /// <returns type="linkFlyScroll" />
        /*
        * linkFlyScroll The included properties are primarily initialized or redefined in this function:
        * isDrag: Whether you are dragging the scroll bar
        * startTop: The scrollbar starts to scroll
        * endTop: The scroll bar ends at the scroll position
        * topLimit: Limit position at the top of the scroll bar
        * bottomLimit: Scroll bar bottom limit position
        * context: content Dom
        * scrollRadix: Rolling base
        * target: The container Dom
        */
        // Reset or read 1 Series data
        var currScroll = this;
        currScroll.isDrag = false,
        currScroll.startTop = 0,
        currScroll.endTop = (currScroll.scrollUl.style.top ? parseInt(currScroll.scrollUl.style.top) : 0),
        currScroll.topLimit = currScroll.target.scrollTop,
        currScroll.bottomLimit = currScroll.target.clientHeight,
        currScroll.scrollRadix = 10;
        // Get the height of the scroll bar: content height *( Height of the container / Content high = Containers as a percentage of content )
        var scrollPx = currScroll.target.clientHeight * (currScroll.target.clientHeight / currScroll.context.offsetHeight);
        // Scroll bar height
        currScroll.scrollUl.childNodes[1].style.height = scrollPx + 'px';
        if (currScroll.context.clientHeight <= currScroll.target.clientHeight && currScroll.options.auto) {
            currScroll.scrollUl.style.display = 'none';
        } else {
            currScroll.scrollUl.style.display = 'block';
            // When the scroll bar is displayed, correct the maximum position data
            currScroll.bottomLimit -= currScroll.scrollUl.offsetHeight;
        }
        // Set the scrolling cardinality of the scroll bar (the scroll bar does not scroll) 1px Content scrolling pixel) : ( Content high - Height of the container [ Because the current container is already displayed 1 screen ])/ The scroll bar top (scrollbar blank scrollable height)
        currScroll.scrollRadix = (currScroll.context.offsetHeight - currScroll.target.clientHeight) / currScroll.bottomLimit;
        return currScroll;
    };
    linkFlyScroll.prototype.init.prototype.roll = function (value) {
        /// <summary>
        ///     1: Scroll bar offset method
        ///         1.1 - roll(value) - Scroll bar scroll method
        /// </summary>
        /// <param name="value" type="Int">
        ///     The scroll bar targets the percentage of scrolling
        /// </param>
        /// <returns type="linkFlyScroll" />
        var currScroll = this;
        if (typeof (value) !== 'number') {
            return currScroll;
        }
        var currTop = (currScroll.bottomLimit - currScroll.topLimit) * value / 100;
        currScroll.scrollEvent(currTop);
        currScroll.endTop = currTop;
        return currScroll;
    };
    /*
    * Utility class
    */
    var tool = {
        setClass: function (element, className) {
            /// <summary>
            ///     1: Sets the element node class attribute
            ///         1.1 - setClass(element,className) - Sets the element node class Property, which creates the node if it is not present, and returns the modified node object
            /// </summary>
            /// <param name="element" type="Element Or String">
            ///     The incoming String The node is created, otherwise it is modified
            /// </param>
            /// <param name="className" type="String">
            ///     Class Name
            /// </param>
            /// <returns type="Element" />
            if (typeof element === 'string') {
                element = document.createElement(element);
            }
            element.className = className;
            return element;
        },
        hasClass: function (element, className) {
            /// <summary>
            ///     1: Determine if the element is present class
            ///         1.1 - hasClass(element,className) - Determine if the element is present class , in the business exception (there is almost no such situation) and there is class return true Otherwise return false
            /// </summary>
            /// <param name="element" type="Element Or String">
            ///     The node object
            /// </param>
            /// <param name="className" type="String">
            ///     Class Name
            /// </param>
            /// <returns type="Element" />
            if (!element || element.nodeType !== 1)// Let the exception pass without processing outside
                return true;
            var elementClassName = element.className;
            if (elementClassName.length < 1) {
                return false;
            }
            if (elementClassName == className || elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) {
                return true;
            }
            return false;
        },
        addClass: function (element, className) {
            /// <summary>
            ///     1: For elements [append] class
            ///         1.1 - addClass(element,className) - For elements [append] class , and return the modified class
            /// </summary>
            /// <param name="element" type="Element Or String">
            ///     The node object
            /// </param>
            /// <param name="className" type="String">
            ///     Class Name
            /// </param>
            /// <returns type="Element" />
            if (!tool.hasClass(element, className)) {
                if (element.className.length < 1) {
                    element.className = className;
                } else {
                    element.className += ' ' + className;
                }
            }
            return element;
        },
        removeClass: function (element, className) {
            /// <summary>
            ///     1: Remove for element class
            ///         1.1 - addClass(element,className) - Remove for element class , and return the modified class
            /// </summary>
            /// <param name="element" type="Element Or String">
            ///     The node object
            /// </param>
            /// <param name="className" type="String">
            ///     Class Name
            /// </param>
            /// <returns type="Element" />
            if (tool.hasClass(element, className)) {
                var reg = new RegExp("(^|\\s)" + className + "(\\s|$)");
                element.className = element.className.replace(reg, '');
            }
            return element;
        },
        css: function (element, key) {
            /// <summary>
            ///     1: Access to elements css The specified property value
            ///         1.1 - css(element,className) - Access to elements css The specified property value
            /// </summary>
            /// <param name="element" type="Element Or String">
            ///     The node object
            /// </param>
            /// <param name="key" type="String">
            ///     To obtain the css attribute
            /// </param>
            /// <returns type="String" />
            return element.currentStyle ? element.currentStyle[key] : document.defaultView.getComputedStyle(element, false)[key];
        },
        addEvent: function (element, type, fn) {
            /// <summary>
            ///     1: Appends events to elements
            ///         1.1 - css(element, type, fn) - Appends an event to an element in a function this Point to the event source
            /// </summary>
            /// <param name="element" type="Element Or String">
            ///     The node object
            /// </param>
            /// <param name="type" type="String">
            ///     Appends the event name without characters on
            /// </param>
            /// <param name="fn" type="Function">
            ///     The event object
            /// </param>
            /// <returns type="void" />
            if (element.attachEvent) {
                element['e' + type + fn] = fn;
                element[type + fn] = function () { element['e' + type + fn](window.event); }
                element.attachEvent('on' + type, element[type + fn]);
            } else if (element.addEventListener) {
                element.addEventListener(type, fn, false);
            }
        },
        //        removeEvent: function (element, type, fn) {
        //            /// <summary>
        //            ///     1: Is an element deletion event that is not used in this function
        //            ///         1.1 - removeEvent(element, type, fn) - Delete events for elements
        //            /// </summary>
        //            /// <param name="element" type="Element Or String">
        //            ///     The node object
        //            /// </param>
        //            /// <param name="type" type="String">
        //            ///     The deleted event name
        //            /// </param>
        //            /// <param name="key" type="String">
        //            ///     The function name of the deleted event
        //            /// </param>
        //            /// <returns type="void" />
        //            if (element.detachEvent) {
        //                element.detachEvent('on' + type, element[type + fn]);
        //                element[type + fn] = null;
        //            } else if (element.removeEventListener) {
        //                element.removeEventListener(type, fn, false);
        //            }
        //        },
        addScrollEvent: function (element, fn) {
            /// <summary>
            ///     1: additional ScrollEvent The event
            ///         1.1 - addScrollEvent(element,fn) - Append to the element ScrollEvent Events (special events, mouse wheel scrolling events on elements)
            /// </summary>
            /// <param name="element" type="Element Or String">
            ///     Element nodes
            /// </param>
            /// <param name="fn" type="Function">
            ///     Event method
            /// </param>
            /// <returns type="void" />
            var bindScrollFn = function (e) {
                e = e || window.event;
                // Determine the rolling direction of the roller: Firefox It's different from other browsers
                e.wheel = (e.wheelDelta ? e.wheelDelta : -e.detail) > 0 ? 1 : -1; // Judge the mouse wheel reverse by the event, 1 Is up, -1 Is down
                // Block browser default behavior
                if (e.preventDefault) { //ff
                    e.preventDefault();
                } else {
                    e.returnValue = false; //ie
                }
                fn.call(element, e);
            }
            if (document.addEventListener) {
                //ff
                element.addEventListener('DOMMouseScroll', bindScrollFn, false);
                //w3c
                element.addEventListener('mousewheel', bindScrollFn, false);
            } else//ie
            {
                element.attachEvent('onmousewheel', bindScrollFn);
            }
        },
        getEvent: function () {
            /// <summary>
            ///     1: To obtain Event object
            ///         1.1 - getEvent() - Get without parameters Event Object, while handling compatibility IE and FF
            /// </summary>
            /// <returns type="Event" />
            if (document.all) {
                return window.event;
            }
            func = getEvent.caller;
            while (func != null) {
                var arg0 = func.arguments[0];
                if (arg0) {
                    if ((arg0.constructor == Event || arg0.constructor == MouseEvent) || (typeof (arg0) == "object" && arg0.preventDefault && arg0.stopPropagation)) {
                        return arg0;
                    }
                }
                func = func.caller;
            }
            return null;
        },
        getMousePos: function (ev) {
            /// <summary>
            ///     1: Gets the current mouse coordinates
            ///         1.1 - getMousePos(ev) - Get the current mouse coordinates, handle compatibility, and return the object format: { x: The mouse x coordinates , y: The mouse y coordinates }
            /// </summary>
            /// <param name="ev" type="Event">
            ///     Event The event object
            /// </param>
            /// <returns type="Json" />
            if (!ev) {
                ev = currScroll.getEvent();
            }
            if (ev.pageX || ev.pageY) {
                return {
                    x: ev.pageX,
                    y: ev.pageY
                };
            }
            if (document.documentElement && document.documentElement.scrollTop) {
                return {
                    x: ev.clientX + document.documentElement.scrollLeft - document.documentElement.clientLeft,
                    y: ev.clientY + document.documentElement.scrollTop - document.documentElement.clientTop
                };
            }
            else if (document.body) {
                return {
                    x: ev.clientX + document.body.scrollLeft - document.body.clientLeft,
                    y: ev.clientY + document.body.scrollTop - document.body.clientTop
                };
            }
        },
        extend: function (oldObj, newObj) {
            /// <summary>
            ///     1: Merge the two objects
            ///         1.1 - extend(oldObj,newObj) - Merge the two objects and return the merged object clone So it will not have any effect on the two objects
            /// </summary>
            /// <param name="oldObj" type="Object">
            ///     The object to be merged A , which ACTS as the base object and overrides the property of the same name of the new object into the base object
            /// </param>
            /// <param name="newObj" type="Object">
            ///     The object to be merged B
            /// </param>
            /// <returns type="Object" />
            var tempObj = tool.clone(oldObj);
            for (var key in newObj) {
                if (newObj.hasOwnProperty(key) && !tempObj.hasOwnProperty(key)) {
                    tempObj[key] = newObj[key];
                }
            }
            return tempObj;
        },
        clone: function (obj) {
            /// <summary>
            ///     1: cloning 1 An object
            ///         1.1 - clone(obj) - cloning 1 Object, and returns the cloned new object whose prototype is the cloned object
            /// </summary>
            /// <param name="obj" type="Object">
            ///     The object to clone
            /// </param>
            /// <returns type="Object" />
            function Clone() { }
            Clone.prototype = obj;
            var newObj = new Clone();
            for (var key in newObj) {
                if (typeof newObj[key] == "object") {
                    newObj[key] = tool.clone(newObj[key]);
                }
            }
            return newObj;
        },
        convertValue: function (value) {
            /// <summary>
            ///     1: Converts a value to a valid value
            ///         1.1 - convertValue(value) - will Json Configuration of the css Convert the value to a valid value, please ensure value The value of the "auto"
            /// </summary>
            /// <param name="value" type="Object">
            ///     The value to be converted
            /// </param>
            /// <returns type="Object" />
            var reg = /^\d+$/g;
            if (typeof (value) === 'number' || reg.test(value)) {
                return value + 'px';
            } else
                return value;
        }
    };
    // Registered to window Under the
    window.linkFlyScroll

Related articles: