AngualrJS中每次$http請求時的一個遮罩層Directive

Darren Ji發表於2016-01-26

 

在AngualrJS中使用$http每次向遠端API傳送請求,等待響應,這中間有些許的等待過程。如何優雅地處理這個等待過程呢?

如果我們在等待過程中彈出一個遮罩層,會是一個比較優雅的做法。

這就涉及到了對$http的請求響應進行攔截了。請求的時候,彈出一個遮罩層,收到響應的時候把遮罩層隱藏。

其實,$httpProvider已經為我們提供了一個$httpProvider.interceptors屬性,我們只需要把自定義的攔截器放到該集合中就可以了。

如何表現呢?大致是這樣的:

 

<div data-my-overlay>
    <br/><img src="spinner.gif" /> &nbsp;&nbsp;Loading
</div>

 

顯示載入的圖片被包含在Directive中了,肯定會用到transclusion。

還涉及到一個遮罩層彈出延遲時間的問題,這個我們希望在config中通過API設定,所以,我們有必要建立一個provider,通過這個設定延遲時間。

$http請求響應遮罩層的Directive:

 

(function(){
    var myOverlayDirective =function($q, $timeout, $window, httpInterceptor, myOverlayConfig){
        return {
            restrict: 'EA',
            transclude: true,
            scope: {
                myOverlayDelay: "@"
            },
            template: '<div id="overlay-container" class="onverlayContainer">' +
                            '<div id="overlay-background" class="onverlayBackground"></div>' +
                            '<div id="onverlay-content" class="onverlayContent" data-ng-transclude>' +
                            '</div>' +
                        '</div>',
            link: function(scope, element, attrs){
                var overlayContainer = null,
                    timePromise = null,
                    timerPromiseHide = null,
                    inSession = false,
                    queue = [],
                    overlayConfig = myOverlayConfig.getConfig();
                    
                init();
                
                //初始化
                function init(){
                    wireUpHttpInterceptor();
                    if(window.jQuery) wirejQueryInterceptor();
                    overlayContainer = document.getElementById('overlay-container');
                }
                
                //自定義Angular的http攔截器
                function wireUpHttpInterceptor(){
                
                    //請求攔截
                    httpInterceptor.request = function(config){
                        //判斷是否滿足顯示遮罩的條件
                        if(shouldShowOverlay(config.method, config.url)){
                            processRequest();
                        }
                        return config || $q.when(config);
                    };
                    
                    //響應攔截
                    httpInterceptor.response = function(response){
                        processResponse();
                        return response || $q.when(response);
                    }
                    
                    //異常攔截
                    httpInterceptor.responseError = function(rejection){
                        processResponse();
                        return $q.reject(rejection);
                    }
                }
                
                //自定義jQuery的http攔截器
                function wirejQueryInterceptor(){
                
                    $(document).ajaxStart(function(){
                        processRequest();
                    });
                    
                    $(document).ajaxComplete(function(){
                        processResponse();
                    });
                    
                    $(document).ajaxError(function(){
                        processResponse();
                    });
                }
                
                //處理請求
                function processRequest(){
                    queue.push({});
                    if(queue.length == 1){
                        timePromise = $timeout(function(){
                            if(queue.length) showOverlay();
                        }, scope.myOverlayDelay ? scope.myOverlayDelay : overlayConfig.delay);
                    }
                }
                
                //處理響應
                function processResponse(){
                    queue.pop();
                    if(queue.length == 0){
                        timerPromiseHide = $timeout(function(){
                            hideOverlay();
                            if(timerPromiseHide) $timeout.cancel(timerPromiseHide);
                        },scope.myOverlayDelay ? scope.myOverlayDelay : overlayConfig.delay);
                    }
                }
                
                //顯示遮罩層
                function showOverlay(){
                    var w = 0;
                    var h = 0;
                    if(!$window.innerWidth){
                        if(!(document.documentElement.clientWidth == 0)){
                            w = document.documentElement.clientWidth;
                            h = document.documentElement.clientHeight;
                        } else {
                            w = document.body.clientWidth;
                            h = document.body. clientHeight;
                        }
                    }else{
                        w = $window.innerWidth;
                        h = $window.innerHeight;
                    }
                    var content = docuemnt.getElementById('overlay-content');
                    var contetWidth = parseInt(getComputedStyle(content, 'width').replace('px',''));
                    var contentHeight = parseInt(getComputedStyle(content, 'height').replace('px',''));
                    
                    content.style.top = h / 2 - contentHeight / 2 + 'px';
                    content.style.left = w / 2 - contentWidth / 2 + 'px';
                    
                    overlayContainer.style.display = 'block';
                }
                
                function hideOverlay(){
                    if(timePromise) $timeout.cancel(timerPromise);
                    overlayContainer.style.display = 'none';
                }
                
                //得到一個函式的執行結果
                var getComputedStyle = function(){
                
                    var func = null;
                    
                    if(document.defaultView && document.defaultView.getComputedStyle){
                        func = document.defaultView.getComputedStyle;
                    } else if(typeof(document.body.currentStyle) !== "undefined"){
                        func = function(element, anything){
                            return element["currentStyle"];
                        }
                    }
                    
                    return function(element, style){
                        reutrn func(element, null)[style];
                    }
                }();
                
                //決定是否顯示遮罩層
                function shouldShowOverlay(method, url){
                    var searchCriteria = {
                        method: method,
                        url: url
                    };
                    
                    return angular.isUndefined(findUrl(overlayConfig.exceptUrls, searchCriteria));
                }
                
                function findUrl(urlList, searchCriteria){
                    var retVal = undefined;
                    angular.forEach(urlList, function(url){
                        if(angular.equals(url, searchCriteria)){
                            retVal = true;
                            return false;//推出迴圈
                        }
                    })
                    return retVal;
                }
            }
        }
    };

    //配置$httpProvider
    var httpProvider = function($httpProvider){
        $httpProvider.interceptors.push('httpInterceptor');
    };
    
    //自定義interceptor
    var httpInterceptor = function(){
      return  {};
    };
    
    
    //提供配置
    var myOverlayConfig = function(){
        //預設配置
        var config = {
            delay: 500,
            exceptUrl: []
        };
        
        //設定延遲
        this.setDelay = function(delayTime){
            config.delay = delayTime;
        }
        
        //設定異常處理url
        this.setExceptionUrl = function(urlList){
            config.exceptUrl = urlList;
        };
        
        //獲取配置
        this.$get = function(){
            return {
                getDelayTime: getDelayTime, 
                getExceptUrls: getExceptUrls,
                getConfig: getConfig
            }
            
            function getDelayTime(){
                return config.delay;
            }
            
            function getExeptUrls(){
                return config.exceptUrls;
            }
            
            function getConfig(){
                return config;
            }
        };
    };
    
    
    var myDirectiveApp = angular.module('my.Directive',[]);
    myDirectiveApp.provider('myOverlayConfig', myOverlayConfig);
    myDirectiveApp.factory('httpInterceptor', httpInterceptor);
    myDirectiveApp.config('$httpProvider', httpProvider);
    myDirectiveApp.directive('myOverlay', ['$q', '$timeout', '$window', 'httpInceptor', 'myOverlayConfig', myOverlayDirective]);
}());

 

在全域性配置中:

 

(functioin(){
    angular.module('customersApp',['ngRoute', 'my.Directive'])
        .config(['$routeProvider, 'myOverlayConfigProvider', funciton($routeProvider, myOverlayConfigProvider){
                ...
                myOverlayConfigProvider.setDealy(100);
                myOverlayConfigProvider.setExceptionUrl({
                    method: 'GET',
                    url: ''
                });
        }]);
}());

 

相關文章