index.js 11.7 KB
Newer Older
Y
Your Name 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
(function () {
    /**
     * @name 滚动加载
     * @author 广州银云信息科技有限公司
     */
    'use strict';
    angular.module('eolinker.directive')
        .value('THROTTLE_MILLISECONDS', null)
        .directive('infiniteScroll', ['$rootScope', '$window', '$interval', 'THROTTLE_MILLISECONDS', function ($rootScope, $window, $interval, THROTTLE_MILLISECONDS) {
            return {
                scope: {
                    infiniteScroll: '&',
                    infiniteScrollContainer: '=',
                    infiniteScrollDistance: '=',
                    infiniteScrollDisabled: '=',
                    infiniteScrollCancel: '=',
                    infiniteScrollUseDocumentBottom: '=',
                    infiniteScrollListenForEvent: '@'
                },
                link: function (scope, elem, attrs) {
                    var changeContainer, lastScrollTop, checkInterval, checkWhenEnabled, container, handleInfiniteScrollContainer, handleInfiniteScrollDisabled, handleInfiniteScrollDistance, handleInfiniteScrollUseDocumentBottom, handler, height, immediateCheck, offsetTop, pageYOffset, scrollDistance, scrollEnabled, throttle, unregisterEventListener, useDocumentBottom, windowElement;
                    windowElement = angular.element($window);
                    scrollDistance = null;
                    scrollEnabled = null;
                    checkWhenEnabled = null;
                    container = null;
                    immediateCheck = true;
                    useDocumentBottom = false;
                    unregisterEventListener = null;
                    checkInterval = false;
                    lastScrollTop = 0;
                    height = function (elem) {
                        elem = elem[0] || elem;
                        if (isNaN(elem.offsetHeight)) {
                            return elem.document.documentElement.clientHeight;
                        } else {
                            return elem.offsetHeight;
                        }
                    };
                    offsetTop = function (elem) {
                        if (!elem[0].getBoundingClientRect || elem.css('none')) {
                            return;
                        }
                        return elem[0].getBoundingClientRect().top + pageYOffset(elem);
                    };
                    pageYOffset = function (elem) {
                        elem = elem[0] || elem;
                        if (isNaN(window.pageYOffset)) {
                            return elem.document.documentElement.scrollTop;
                        } else {
                            return elem.ownerDocument.defaultView.pageYOffset;
                        }
                    };
                    handler = function () {
                        var containerBottom, containerTopOffset, elementBottom, remaining, shouldScroll, scrollTop;
                        if (container === windowElement) {
                            containerBottom = height(container) + pageYOffset(container[0].document.documentElement);
                            var elemHeight = height(elem)
                            elementBottom = offsetTop(elem) + elemHeight;
                            // scrollTop = elemHeight - elementBottom;
                        } else {
                            containerBottom = height(container);
                            containerTopOffset = 0;
                            if (offsetTop(container) !== void 0) {
                                containerTopOffset = offsetTop(container);
                            }
                            var elemHeight = height(elem);
                            elementBottom = offsetTop(elem) - containerTopOffset + elemHeight;
                            // scrollTop = elemHeight - elementBottom;
                        }
                        if (useDocumentBottom) {
                            elementBottom = height((elem[0].ownerDocument || elem[0].document).documentElement);
                        }
                        // if(scrollTop>lastScrollTop){
                        //     shouldScroll = remaining <= height(container) * scrollDistance + 1;
                        //     //向下滚动
                        // }else{
                        //     //向上滚动
                        //     shouldScroll = remaining <= height(container) * scrollDistance + 1;
                        // }
                        remaining = elementBottom - containerBottom;
                        shouldScroll = (remaining <= (height(container) * scrollDistance*0.1))&&elementBottom;
                        // lastScrollTop=scrollTop;
                        if (shouldScroll) {
                            checkWhenEnabled = true;
                            if (scrollEnabled) {
                                if (scope.$$phase || $rootScope.$$phase) {
                                    return scope.infiniteScroll();
                                } else {
                                    return scope.$apply(scope.infiniteScroll);
                                }
                            }
                        } else {
                            if (checkInterval) {
                                $interval.cancel(checkInterval);
                            }
                            return checkWhenEnabled = false;
                        }
                    };
                    throttle = function (func, wait) {
                        var later, previous, timeout;
                        timeout = null;
                        previous = 0;
                        later = function () {
                            previous = new Date().getTime();
                            $interval.cancel(timeout);
                            timeout = null;
                            return func.call();
                        };
                        return function () {
                            var now, remaining;
                            now = new Date().getTime();
                            remaining = wait - (now - previous);
                            if (remaining <= 0) {
                                $interval.cancel(timeout);
                                timeout = null;
                                previous = now;
                                return func.call();
                            } else {
                                if (!timeout) {
                                    return timeout = $interval(later, remaining, 1);
                                }
                            }
                        };
                    };
                    if (THROTTLE_MILLISECONDS != null) {
                        handler = throttle(handler, THROTTLE_MILLISECONDS);
                    }
                    scope.$on('$destroy', function () {
                        container.unbind('scroll', handler);
                        if (unregisterEventListener != null) {
                            unregisterEventListener();
                            unregisterEventListener = null;
                        }
                        if (checkInterval) {
                            return $interval.cancel(checkInterval);
                        }
                    });
                    handleInfiniteScrollDistance = function (v) {
                        return scrollDistance = parseFloat(v) || 0;
                    };
                    scope.$watch('infiniteScrollDistance', handleInfiniteScrollDistance);
                    handleInfiniteScrollDistance(scope.infiniteScrollDistance);
                    handleInfiniteScrollDisabled = function (v) {
                        scrollEnabled = !v;
                        if (scrollEnabled && checkWhenEnabled) {
                            checkWhenEnabled = false;
                            return handler();
                        }
                    };
                    scope.$watch('infiniteScrollDisabled', handleInfiniteScrollDisabled);
                    handleInfiniteScrollDisabled(scope.infiniteScrollDisabled);
                    handleInfiniteScrollUseDocumentBottom = function (v) {
                        return useDocumentBottom = v;
                    };
                    scope.$watch('infiniteScrollUseDocumentBottom', handleInfiniteScrollUseDocumentBottom);
                    handleInfiniteScrollUseDocumentBottom(scope.infiniteScrollUseDocumentBottom);
                    changeContainer = function (newContainer) {
                        if (container != null) {
                            container.unbind('scroll', handler);
                        }
                        container = newContainer;
                        if (newContainer != null) {
                            return container.bind('scroll', handler);
                        }
                    };
                    changeContainer(windowElement);
                    if (scope.infiniteScrollListenForEvent) {
                        unregisterEventListener = $rootScope.$on(scope.infiniteScrollListenForEvent, handler);
                    }
                    handleInfiniteScrollContainer = function (newContainer) {
                        if ((newContainer == null) || newContainer.length === 0) {
                            return;
                        }
                        if (newContainer.nodeType && newContainer.nodeType === 1) {
                            newContainer = angular.element(newContainer);
                        } else if (typeof newContainer.append === 'function') {
                            newContainer = angular.element(newContainer[newContainer.length - 1]);
                        } else if (typeof newContainer === 'string') {
                            newContainer = angular.element(document.querySelector(newContainer));
                        }
                        if (newContainer != null) {
                            return changeContainer(newContainer);
                        } else {
                            throw new Error("invalid infinite-scroll-container attribute.");
                        }
                    };
                    scope.$watch('infiniteScrollContainer', handleInfiniteScrollContainer);
                    scope.$watch('infiniteScrollCancel', function (isCancel) {
                        if (isCancel) {
                            container.unbind('scroll', handler);
                            if (unregisterEventListener != null) {
                                unregisterEventListener();
                                unregisterEventListener = null;
                            }
                            if (checkInterval) {
                                return $interval.cancel(checkInterval);
                            }
                        } else {
                            changeContainer(angular.element(elem.parent()));
                        }
                    });
                    handleInfiniteScrollContainer(scope.infiniteScrollContainer || []);
                    if (attrs.infiniteScrollParent != null && attrs.infiniteScrollCancel == null) {
                        changeContainer(angular.element(elem.parent()));
                    }
                    if (attrs.infiniteScrollImmediateCheck != null) {
                        immediateCheck = scope.$eval(attrs.infiniteScrollImmediateCheck);
                    }

                    function getFirstFunction(immediateCheck) {
                        if (immediateCheck) {
                            return $interval((function () {
                                return handler();
                            }), 0)
                        } else {
                            return false;
                        }
                    }
                    return checkInterval = getFirstFunction(immediateCheck);
                }
            };
        }]);
})();